2013-05-17 2 views
0

в следующих фрагментах кода, мне нужно защитить connfd, потому что он может часто меняться в вызове accept().Стратегия выбора места блокировки мьютекса и разблокировки в многопоточной программе

void *deal_conn(void *arg){ 
     int connfd; 
     connfd = *((int*)arg); 
     .... 

    } 

    for(;;){ 
    connfd = accept(...); 
    pthread_create(&thread, NULL, deal_conn, &connfd); 
    } 

Я в недоумении, где можно заблокировать и разблокировать мьютексы для этой переменной. Может ли кто-нибудь дать мне несколько идей? спасибо!

+1

connfd передается как указатель - на время действия функции deal_conn это значение может быть изменено. Рассмотрите возможность использования mt-безопасного вызова malloc, чтобы создать отдельную безопасную копию connfd для перехода к функции deal_conn. deal_conn затем может освободить эту переменную. –

+0

Что удерживает вас от блокировки непосредственно перед вызовом 'accept()' и разблокировкой после присвоения дескриптора сокета переменной, связанной с функцией потока? – alk

ответ

2

Не передавайте адрес connfd в каждой теме, динамически выделяйте новый int и передавайте это, и у вас есть нить free(), когда больше не требуется. Поскольку нити больше не разделяют тот же ресурс не требования взаимной блокировки:

connfd = accept(...); 
if (connfd != -1) 
{ 
    int* fd = malloc(sizeof(*fd)); 
    if (fd) 
    { 
     *fd = connfd; 
     pthread_create(&thread, NULL, deal_conn, fd); 
    } 
} 

void *deal_conn(void *arg){ 
    int connfd = *((int*)arg); 

    free(arg); 
} 
+0

думаю есть проблема. хотя значение '* fd' никогда не изменится, значение' fd' может измениться до того, как поток получит свое значение. не так ли? – user1944267

+0

@ пользователь1944267, no it can not. – hmjd

+0

ах, вы имели в виду: даже если новый поток вызывается после того, как возвращается следующий 'accept()', значение 'fd' уже скопировано в стек нового потока? – user1944267

0

Помимо того, я также предпочитаю решение с использованием динамически выделяемым переменным дескриптором сокета, как предложено другими, здесь есть ответ на ОПЫ-х вопрос:

void *deal_conn(void * arg) 
{ 
    int connfd = *((int *) arg); 
    /* unlock mutex here */ 
    ... 
} 

... 

/* init mutex here */ 

for(;;) 
{ 
    /* lock mutex here */ 
    int connfd = accept(...); 
    if (-1 == connfd) 
    { 
    /* in case of error unlock mutex here, as the deal_conn() will not be called */ 
    } 
    else 
    { 
    int result = pthread_create(..., deal_conn, &connfd); 
    if (-1 == result) 
    { 
     /* in case of error unlock mutex here, as the deal_conn() will not be called */ 
    } 
    } 

    ... 
+0

Я думаю, что pthread_create может вернуться до того, как' deal_conn' получит значение из & connfd. – user1944267

+0

@ user1944267: Это нормально, поскольку цикл accept() блокирует вызов блокировки мьютекса до вызова 'accept()', пока мьютекс не был разблокирован 'deal_conn'. – alk

+0

Я думаю, что проблема в коде выше, как вы думаете? – user1944267

0

как об изменении кода, как следующие:

void *deal_conn(void *arg){ 
      int connfd; 
      connfd = (int)arg; 
      .... 

     } 

     for(;;){ 
     connfd = accept(...); 
     pthread_create(&thread, NULL, deal_conn, (void *)connfd); 
     } 

Я не вижу необходимости блокировки connfd, connfd копируется в стек нового потока, не разделяемые потоками.

+0

wow, похоже прохладный. так что даже если connfd равно 4 байтам, (void *) составляет 8 байтов, листинг все еще в порядке? – user1944267

+0

, чтобы избежать проблемы с литьем, (void *) (uint64_t) connfd должен работать – xwlan

+0

Используйте переменную типа 'intptr_t', которая будет передана' pthread_create() ', так как гарантированно будет иметь тот же размер, что и' void * '. – alk

Смежные вопросы