C 언어 에서 협정 실현 사례

3980 단어 C 언어협정
협 정 은 사용자 공간의 비 선점 식 스 레 드 로 주로 대량의 IO 작업 을 기다 리 는 문 제 를 해결 하 는 데 사용 된다.
협정 vs 라인
다 중 스 레 드 를 사용 하여 IO 차단 임 무 를 해결 하 는 것 보다 협 정 을 사용 하 는 장점 은 잠 금 을 추가 하지 않 고 공 유 된 데 이 터 를 방문 하여 동기 화 작업 을 하지 않 아 도 된다 는 것 이다.여기 서 설명 해 야 할 것 은 협 정 을 사용 할 때 자 물 쇠 를 추가 하지 않 아 도 되 는 이 유 는 모든 협 정 이 한 스 레 드 에서 만 운행 되 기 때 문 이 아니 라 협 정의 비 선점 식 특징 때문이다.협 정 을 사용 하면 CPU 를 자발적으로 내 놓 지 않 을 때 까지 다른 협 정 으로 갑자기 전환 되 지 않 는 다 는 것 이다.한편,스 레 드 는 선점 식 입 니 다.다 중 스 레 드 를 사용 하면 스 레 드 가 언제 운영 체제 에 의 해 배치 되 고 언제 전환 되 는 지 확인 할 수 없 기 때문에 잠 금 으로'원자 조작'을 실현 하 는 의미 가 필요 합 니 다.
협정 vs 비동기 반전
사실 더욱 일반적인 방법 은 차단 되 지 않 은 IO(예 를 들 어 비동기 IO,또는 syscall 에서 스스로 실현 하 는 비동기 IO,예 를 들 어 asio)를 사용 하고 처리 작업 을 반전 함수 에 쓰 는 것 이다.이런 방법 은 일반적으로 아무런 문제 가 없 지만,리 셋 함수 가 많아 지면 일 관 된 업무 코드 가 여러 리 셋 함수 로 나 뉘 어 유지 보수 의 원 가 를 증가 시 킬 것 이다.따라서 협 정 을 사용 하면 동기 화 된 쓰기 로 비동기 적 인 코드 를 쓸 수 있다.
static 변 수 를 이용 하여 협정 을 실현 하 다
하나의 협 정 을 실현 하려 면 함수 호출 의 문맥 을 어떻게 저장 하 느 냐 가 중요 하 다.이전에 인터넷 에서 블 로그coroutines in c를 보 았 는데 매우 간결 한 방식 으로 이 상하 문 저장 기능 을 실현 했다.구현 코드 는 다음 과 같 습 니 다:

#define crBegin static int _cr_state = 0; switch(_cr_state) { case 0:
#define crReturn(x) do { _cr_state = __LINE__; return x; case __LINE__:; } while (0)
#define crFinish }

int func1() {
    crBegin
    while (1)
    {
        printf("hello world
"); crReturn(0); } crFinish }
이 코드 는 함수 의 static 변 수 를 이용 하여 함수 호출 상 태 를 저장 합 니 다.주의,vs 2013 디 버 깅 기능 이 있 기 때문에 vs 2013 의LINE__상수 가 아니 기 때문에 컴 파일 이 통과 되 지 않 고 gcc 를 사용 하면 컴 파일 할 수 있 습 니 다.이 코드 는 간단 하지만 문제 가 있 습 니 다.예 를 들 어 두 개의 협 정 이 같은 함 수 를 호출 하면 오류 가 발생 할 수 있 습 니 다.따라서 블 로그 에서 이 코드 를 언급 하 는 것 은 주로 하나의 방향 을 제시 하 는 것 이다.만약 에 실제 사용 하면 이렇게 하면 안 될 것 이다.
setjmp,longjmp 를 이용 하여 협정 을 실현 하 다
앞에서 말 했 듯 이 협 정 을 실현 하 는 가장 중요 한 것 은 함수 호출 을 저장 하 는 문맥 이 고 이런 문맥 은 주로 두 부분 에 있 습 니 다.1.각 레지스터 의 값,2.함수 호출 스 택 입 니 다.C 언어 에 서 는 함수 호출 시 각 레지스터 의 값 을 setjmp 를 통 해 저장 할 수 있 습 니 다.저장 하면 longjmp 를 통 해 당초 setjmp 의 곳 으로 재현 할 수 있 습 니 다(크로스 함수 로 이해 할 수 있 는 goto).그러나 주의해 야 할 것 은 setjmp 는 레지스터 의 값 만 저장 하고 함수 호출 스 택 을 유지 하 는 것 은 책임 지지 않 습 니 다(이것 은 setjmp 의 jmp 를 보 세 요.buf 의 구 조 를 알 수 있 습 니 다)따라서 사용자 가 수 동 으로 이 함수 호출 스 택 을 유지 해 야 합 니 다.setjmp,longjmp 를 사용 하 는 흔 한 오 류 는 이미 실 행 된 함수 로 longjmp 를 시도 하 는 것 입 니 다.이때 레지스터 의 값 은 당시 에 저 장 된 값 이지 만 호출 스 택 은 원래 의 호출 스 택 이 아 닙 니 다.
제 방법 은 협 정 을 만 들 때 더미 위 에 공간(크기 2M)을 협 정의 호출 스 택 으로 신청 한 다음 에 setjmp 를 만 들 때 레지스터 esp 의 값 을 수 동 으로 변경 하여 제 가 만 든 호출 스 택 을 가리 키 는 것 입 니 다.그래서 앞으로 실 행 될 때 이 협 정 은 내 가 제공 한 메모 리 를 창고 로 사용 할 것 이다.
나의 이 협 정 고 는 세 개의 인 터 페 이 스 를 제공 했다.
  • coro_new:협 정 생 성
  • coro_yield:제어 권 을 스케줄 러 에 게 되 돌려 줍 니 다
  • coro_main:운영 스케줄 러
  • 협 정의 제어 절 차 는 다음 과 같다.
  • coro 통과 하기main 은 스케줄 협 정 을 실행 하고 다음 운행 의 협 정 을 찾 아 운행 합 니 다.
  • 이 협 정 을 실행 할 때 까지 coroyield 는 통제 권 을 스케줄 러 에 반환 합 니 다.
  • 모든 협 정 이 실 행 될 때 까지 상기 두 단 계 를 반복 한다.
  • 이 협 정 라 이브 러 리 는 매우 간단 하고 100 여 줄 의 코드 만 있 습 니 다.물론 그것 을 실현 하 는 목적 은 가장 간단 한 협 정 모델 을 제공 하 는 것 입 니 다.기능 이 완전 하고 노 스틱 성 이 강 한 실제 업무 운행 에 투입 할 수 있 는 협 정 이 아 닙 니 다.
    그래서 문 제 는 많다.
  • 예 를 들 어 협 정 에서 스 택 을 2M 이상 호출 할 때 이것 은 처리 해 야 한다.현재 의 코드 는 하지 않 았 기 때문에 프로그램 을 중단 하고 나 쁜 더 미 를 쓰 지 않도록 해 야 한다.무 작위 로 재현 할 수 없 는 문제 가 발생 해 야 한다.
  • 분명히 실현 할 때 다 중 스 레 드 를 고려 하지 않 았 고 다 중 스 레 드 환경 에서 실행 되면 코드 를 동기 화 처리 해 야 한다.
  • 현재 이 버 전의 협 정 은 협 정 에서 호출 된 함수 가 syscall 에 막 히 지 않 는 다 는 약속 이 있 는데 이것 은 분명 과학적 이지 않다.하나의 완전한 협 정 라 이브 러 리 는 자주 사용 하 는 syscall 의 비 차단 실현 을 포함 해 야 합 니 다.왜냐하면 하나의 스 레 드 만 이 호출 에 막 을 수 없 기 때 문 입 니 다.
  • 총결산
    물론 협 정 을 실현 하 는 데 더 좋 은 방법 도 있다.예 를 들 어 glibc 의 uontext 라 이브 러 리 를 사용 할 수 있다 면 이 라 이브 러 리 를 바탕 으로 이 루어 질 수 있 고 자신 이 수 동 으로 함수 호출 의 문맥 을 관리 하지 않 아 도 된다.예 를 들 어 구름 바람 이 실현 하 는 협 정 라 이브 러 리 와 같다.
    여기 서 C 언어 에서 의 협상 실현 사례 에 관 한 이 글 은 여기까지 소개 되 었 습 니 다.더 많은 C 언어 실현 협상 내용 은 우리 의 이전 글 을 검색 하거나 아래 의 관련 글 을 계속 조회 하 시기 바 랍 니 다.앞으로 많은 응원 바 랍 니 다!

    좋은 웹페이지 즐겨찾기