один поток для выхода из них всех

#c #multithreading #sockets #winapi

#c #многопоточность #сокеты #winapi

Вопрос:

У меня есть основная программа, которая генерирует несколько потоков (используя цикл while с accept() для получения клиентов), и все, что ей нужно сделать, это «слушать клавиатуру», и когда пользователь вводит слово exit, оно закрывает всю программу. сначала основная программа создает поток прослушивания, затем он входит в цикл while, который принимает клиентов. даже если слушающий поток получает ввод exit, цикл все еще застревает на accept.

мне не нужно использовать отдельный поток для прослушивания клавиатуры, но я не смог найти способ блокировки, который бы работал.

прослушивающий поток:

 DWORD WINAPI ListenService(LPVOID lpParam)
{
    char buffer[5];
    if (EOF == scanf("%s", buffer))
    {
        printf("faile get word from keyboardn");
    }
    if (buffer[4] != '')
        strcat(buffer, "");
    if (STRINGS_ARE_EQUAL(buffer, "exit"))
    {
        return 999;
    }
    return -1;
}
 

в основном коде:

 ThreadListen = CreateThread(NULL,0,ListenService,NULL,0,amp;(ThreadId));   
while(1)
{
    SOCKET AcceptSocket = accept(MainSocket, NULL, NULL);
    if (AcceptSocket == INVALID_SOCKET)
    {
        printf("Accepting connection with client failed, error %ldn", WSAGetLastError());
        CleanupWorkerThreads();
        WSACleanup();
    }
    printf("Client Connected.n");
}
 

Комментарии:

1. Не связано, но в документации CreateThread говорится следующее: «Поток в исполняемом файле, который вызывает библиотеку времени выполнения C (CRT), должен использовать функции _beginthreadex and _endthreadex для управления потоками, а не CreateThread and ExitThread » .

2. Вызовите ExitProcess() .

Ответ №1:

Есть много разных способов справиться с этим.

Вы можете прервать блокировку accept() , просто закрыв прослушивающий сокет.

Или вы можете использовать select() с коротким таймаутом, чтобы определить, когда новый клиент ожидает перед вызовом accept() . Вы можете проверить свое условие выхода между вызовами select() . Просто имейте в виду, что существует небольшое условие гонки, при котором клиент может отключиться между временем select() и accect() вызовом, поэтому все равно accept() может блокироваться, если больше нет ожидающих клиентов.

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

Или вы можете использовать асинхронные сокеты, используя WSACreateEvent() , WSAEventSelect() , и WSAWaitForMultipleEvents() для обнаружения активности сокета. Затем вы можете создать событие добавления для ожидания, когда произойдет условие выхода.

Или вы можете использовать порт завершения ввода-вывода для обработки активности сокета, а затем вы можете отправить пользовательский пакет выхода в очередь IOCP, используя PostQueuedCompletionStatus() для «пробуждения» любых ожидающих потоков.

Комментарии:

1. я думаю, что опция выбора может быть решением, которое я ищу, я попытался прочитать select в Windows doc, но смог найти способ использовать его для обнаружения нового клиента, которого я жду, и, возможно, вы можете подробнее рассказать об этой опции?

2. @dinohayon прослушивающий сокет находится в состоянии чтения, когда у него есть клиент, ожидающий принятия. Так что просто вызывайте select() запрос для удобства чтения, используя an fd_set , содержащий прослушивающий сокет. Если прослушивающий сокет доступен для чтения, FD_ISSET() он сообщит true для этого сокета fd_set после select() выхода.