2014-02-13 2 views
1

Это не ошибка в коде, но для того, чтобы понять, как выполнить следующие критерии. Я видел аналогичные вопросы here и here, но не получил никакого конкретного способа сделать это.Уведомлять родителя о завершении потока

Рассмотрим следующие части кода:

.... 

pthread_create(&Receiver,NULL,ReceiveFromServer,(void*)&ClientSoc); 
sending =1; 
while (sending) 
{ 
    SHOW_PROMPT; 
    gets(message); 
    memcpy(Packet.data,message,MAX_DATA_LENGTH); 
    if (SetCommand(&Packet,message) == CMD_EXT) 
     sending = 0; 
    send(ClientSoc,&Packet,PACKET_SIZE,0); 
} 
close(ClientSoc); 
pthread_join(Receiver,NULL); 
return 0; 
.... 

И в ReceiveFromServer функции:

void* ReceiveFromServer(void* ClientSoc) 
{ 
    int receiving =1; 
    int Status; 
    strPacket Packet; 
    while(receiving) 
    { 
     if(recv(*(int*)ClientSoc,&Packet,PACKET_SIZE,0)>0) 
     { 
      ParseReply(Packet); 
      SHOW_PROMPT; 
     } 
     if(GET_COMMAND(Packet.Header) == CMD_EXT) 
      receiving = 0; 
    } 
    return NULL; 
} 

Пусть все объявленную или определено правильно.

Таким образом, поток прекращается в зависимости от полученных данных с сервера, но отправитель все еще работает, поскольку он не знает, что приемник завершен. Отправитель только выходит из цикла в зависимости от пользовательского ввода (конкретное слово, например «exit»).
Как уведомить родителя о завершении потока?
Я попытался сделать sending глобальным и изменить его изнутри, но это не сработало.

+0

@suufang, я упомянул, что видел этот вопрос, но это не отвечает на эту ситуацию. – Dipto

+0

Опубликуйте полный пример, демонстрирующий вашу проблему. _Assume все объявлено или определено правильно_ - это предположение вызывает у вас проблемы в 100% случаев. –

+0

Я этого не понимаю. Если приемник завершается в зависимости от того, что он получил от отправителя, отправитель должен знать заранее, что приемник прекратит свое действие, и, следовательно, этот отправитель может прекратить работу после отправки завершающих данных получателю, не так ли? – alk

ответ

1

В основном цикле родителей заменить:

while (sending) 

с:

while (sending && pthread_kill(Receiver, 0) != ESRCH) 

Это будет проверять наличие Receiver нити. См. How do you query a pthread to see if it is still running? для получения дополнительной информации.

Однако следует отметить, что How do I determine if a pthread is alive? подчеркивает, что вы не можете сделать это для отдельной нити. И http://man7.org/linux/man-pages/man3/pthread_kill.3.html гласит:

POSIX.1-2008 рекомендует, если реализация определяет использование нити ID после окончания срока службы, pthread_kill() должен возвращать ESRCH ошибки. Реализация glibc возвращает эту ошибку в случаях, когда обнаружен недопустимый идентификатор потока. Но обратите внимание также, что POSIX говорит, что попытка использовать идентификатор потока, срок службы которого закончился, приводит к неопределенному поведению, и попытка использовать недопустимый идентификатор потока при вызове pthread_kill() может, например, вызвать ошибку сегментации.

Закрытие сокета в ReceiveFromServer потоке, когда вы получаете CMD_EXT, вероятно, также работает, так как Are parallel calls to send/recv on the same socket valid? кажется, указывает POSIX сокеты поточно. Но R. настоятельно рекомендует против этого в Is closesocket thread safe?. И RHEL5 Linux man 2 close заявляет:

Это, вероятно, неразумно закрывать дескрипторы файлов в то время как они могут быть в использовании системных вызовов в других потоках в одном процессе.Поскольку дескриптор файла может быть повторно использован, существуют некоторые неясные условия гонки, которые могут вызывать непреднамеренные побочные эффекты.

Если вы имеете дело со сокетами, вы должны быть уверены, что в другом потоке нет блокировки (2), иначе он может блокироваться навсегда, поскольку больше не будет отправлено сообщений через сокет. Обязательно используйте выключение (2), чтобы закрыть все части соединения, прежде чем закрыть розетку.

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

И, конечно, вам нужно будет добавить обработку ошибок сокета, но это выходит за рамки этого вопроса.

0

Возможно, вы можете попытаться использовать pthread_tryjoin_np (я никогда не использовал его) в родительском цикле, чтобы определить, завершен ли поток. Он доступен только для Linux, как я понял.

2

Закройте сокет в потоке ReceiveFromServer, когда вы получите CMD_EXT. Посылающий поток должен получить сообщение достаточно скоро - вызов send() вернется с ошибкой.

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