2012-02-26 4 views
1

현재 작업하고있는 응용 프로그램은 select()를 사용하여 클라이언트와의 연결을 관리하는 서버입니다. 서버가 메시지를 수신 할 때마다 소켓을 읽기 위해 새 스레드가 열립니다. 그 시간 동안 소켓의 파일 디스크립터는 세트로부터 제거되고, 읽기 마지막에 추가 될 것이다. 여기 코드의 샘플입니다FD_SET, FD_CLR ... 원자 적 연산입니까?

struct s_handle { 
int sock; 
fd_set * rdfs; 
}; 




int main(){ 
... 
fd_set rdfs; 
... 
while(1){ 
.... 
    select(nb_fd,&rdfs,NULL,NULL,NULL) 
    for_each(peer){ 
    if(FD_ISSET(peer->sock,&rdfs)){ 
    struct s_handle * h = malloc(sizeof(struct s_handle)); 
    h->sock = peer->sock; 
    h->rdfs = &rdfs; 
    FD_CLR(peer->sock,&rdfs); 
    pthread_create(thread,NULL,handle,(void *)&h); 
    } 
    } 
... 
} 
... 
} 

void* handle(void* argss){ 
struct s_handle * temp = (struct s_handle *) argss; 
... 
FD_SET(temp->sock,temp->rdfs); 
} 

합니까 FD_SET, FD_ISSET 및 FD_CLR 원자 조작, 또는 내가 뮤텍스와 RDFS를 잠글 필요합니까?

뮤텍스가 필요한 경우 어떻게 교착 상태를 피할 수 있습니까?

답변

3

먼저 스레드를 만들어서는 안됩니다. 스레드를 만드는 것은 상당히 높은 오버 헤드 작업이므로 더 많은 작업을해야하기 때문에 스레드 스레드가 더 필요할 때만 사용해야합니다.

그리고 예, 뮤텍스로 FD_* 함수를 보호해야합니다. 일반적인 해결 방법은 FD_* 작업을 수행하는 데 필요한 초 단위로만 보유한 뮤텍스를 유지하는 것입니다. select을 호출하기 전에 뮤텍스를 획득하고 디스크립터 세트의 복사본을 만든 다음 뮤텍스를 릴리스하십시오.

일반적으로 읽기 세트에서 소켓을 제거하는 것은 좋지 않습니다. 소켓을 다시 읽기 세트에 넣으면 나중에 나중에 발생하는 select이 변경되지 않습니다. 그리고 새로운 세트를 조작하기 위해서 selectselect에서 호출하는 스레드를 얻는 방법을 알아내는 것이 엉망이 될 것입니다.

I/O 검색 방법을 재검토하고 자신의 롤백을 시도하는 대신 표준 방법 중 하나를 사용하는 것이 좋습니다. 최근 소켓을 읽었을 때 select이 아직 차단되었거나 소켓을 모두 읽었을 때 select을 다시 연결해야하기 때문에 일부 소켓을 읽지 않아도되는 추한 조건을 강요합니다. 어느 솔루션도 좋지 않습니다.

보다 일반적인 패턴은 소켓을 읽는 동안 세트에 소켓을 유지하고 모든 소켓을 읽을 때까지 select으로 돌아 가지 않는 것입니다 (데이터 처리가 반드시 필요한 것은 아님).

1

이들이 있다는 보장이 없으므로 전혀 신뢰하지 않아야합니다.

fd_set은 종종 일반 비트 맵 (int 또는 유사한 배열)을 사용하여 구현되며 FD_* 매크로는 비트 조작 연산입니다. 이러한 작업은 판형보다 네이티브 인 경우가 거의 없습니다. 기본형 int (그 경우조차도).

1

FD_SET, FD_ISSET 등은 매크로입니다. 저는 여러분이 원자적일 것으로 생각할 수 있다고 생각하지 않습니다. 그러나, 뮤텍스를 사용하는 것보다, 나는 당신의 접근 방식을 다시 생각해 보길 권한다. 읽을 필요가있을 때마다 새 스레드를 만들고 그 결과를 사용하는 스레드와 다른 스레드에서 select을 호출하면 모두 나쁜 아이디어처럼 보입니다. 특별히 이라는 스레드를 사용하여 해당 연결을 완전히 처리하는 대신을 읽어야하는 이유가 있다면 자체적으로 fd_set이 있고 select이라고 부르는 이유는 무엇입니까? 당신이을 경우 질문을 다시 읽기시


, 난 당신이 지금있는 방법을 사용 말하고 싶지만, 당신은 당신의 읽기 fd_setselect에 대한 각 호출하기 전에 다시 만들어야하고,에 의해 수정되는 것을주의해야한다 요구. 따라서 스레드 함수의 끝에있는 FD_SET은 어쨌든 유용하지 않습니다. 왜냐하면 다시 읽을 준비가되지 않은 경우 다음 select 호출에서 설명자를 집합에서 제거 할 것이기 때문입니다. 대신 select 호출 전에 select 스레드에서 읽기 세트를 작성해야하므로 포함시킬 소켓을 결정할 수있는 대체 수단이 필요합니다.

당신은 당신의 s_handle 구조체에 바쁜 플래그를 추가하고, 뮤텍스와 것을 을 보호 할 수 - 당신이 스레드를 생성하고 종료 할 때 그것을 명확 스레드를하기 전에 다음을 설정합니다. 선택 호출 전에 fd_set을 채우는 경우 s_handle 구조체의 플래그에 의해 "사용중"으로 표시되지 않은 각 피어의 소켓을 추가하십시오.

+0

그 스레드가 자신의'fd_set'을 가지며'select' 자체를 호출하게되면, 그 스레드는 단지 I/O를 기다려야 만합니다. 그런 다음 특정 스레드가 스케줄 될 때까지 해당 소켓에서 수행 할 수있는 작업이 없습니다. 그래서 많은 여분의 리소스를 소비하게 될 것입니다. 모든 스레드가 기다리고있을 뿐이며 '올바른'스레드를 실행하려면 추가로 많은 컨텍스트 스위치가 필요합니다. (하지만, 그가'select'를 사용하고 있다면, 그는 아마도 성능에 신경을 쓰지 않을 것입니다.) –

+0

글을 쓸 때 나는 혼란 스럽습니다. repolling없이 그것을 종료합니다. 소켓을 읽는 스레드를 만드는 줄을 더 생각하고 있었고 연결이 닫힐 때까지 주변을 지켜 보았습니다.하지만 그가 그렇게하고있는 것처럼 보이지는 않습니다. – Dmitri

관련 문제