Как выйти из цикла while с активным потоком

Я знаю, что это не лучшая формулировка моего вопроса. На моем сервере некоторые проблемы В ОСНОВНОМ сводятся к следующему: как выйти из цикла while после выполнения условия A? И можно ли уничтожить определенные потоки, если выполняется условие B?

К сожалению, основной поток блокируется функцией recvfrom() навсегда, если я не могу выйти из цикла.

while (1)
{
  recBytes = recvfrom(sock, packetBuff, 8, 0, (struct sockaddr *) &client, &SockLength);

  std::thread TX([&] 
  {
    //process packet task

    if(conditionA == 1)
      break from while loop

    if(conditionB == 1)
      destroy any active threads spawned by TX

    .
    .
    .
    much more tasks

  });

  TX.detach();
} 

.
.
.
continue rest of code

Заранее спасибо!


person djent    schedule 16.06.2017    source источник
comment
Рассматривали ли вы использование какой-либо библиотеки asio? На ум приходит boost.asio, но есть и другие доступные библиотеки. Несмотря на то, что в указанном случае закрытие сокета из другого потока является простым и достаточно эффективным, чтобы выйти из recv_from и проверить случай ошибки, как я надеюсь, вы уже делаете. Оператор break завершает цикл.   -  person Michaël Roy    schedule 16.06.2017
comment
Могу ли я предложить эту лекцию на YT: История времени: асинхронный C++ - Стивен Симпсон? Стоит потратить время, прежде чем разрабатывать клиент-серверное приложение с использованием современных методов C++. Независимо от желаемого размера вашего приложения.   -  person Michaël Roy    schedule 16.06.2017
comment
@MichaëlRoy Не могли бы вы показать мне в коде, как это будет выглядеть, пожалуйста?   -  person djent    schedule 16.06.2017
comment
Проверьте образцы кода boost.asio: boost.org/doc/libs/1_64_0/doc/html/boost_asio/example/cpp11/. Обратите внимание, что сервер может обрабатывать множество клиентов, работая в одном потоке. Код из презентации выше: github.com/stevejims/acpp. Часть этого кода может обрабатывать 50+ тысяч одновременных запросов при работе в одном потоке, что всегда интересно.   -  person Michaël Roy    schedule 16.06.2017
comment
Почему вы хотите выйти из цикла? Это эффективно убьет вашего демона.   -  person Michaël Roy    schedule 16.06.2017


Ответы (1)


Стандартный способ отказаться от блокирующего вызова ввода-вывода — заменить его вызовом select()/poll()/etc, который ожидает 2 сокета: ваш сокет данных и неблокирующий канал уведомлений. Если select() сообщает, что вы можете читать или писать в сокет данных, вы делаете именно это, неблокирующим образом. Если он сообщает, что данные доступны в канале уведомлений, вы выходите из цикла. Любой поток может записать один байт в неблокирующий канал уведомлений, чтобы вызвать возврат select() в другом потоке.

Что касается уничтожения других потоков, вы не можете сделать это без сотрудничества с этими потоками. По сути, вам нужен способ уведомить их о том, что им нужно бросить курить. Если эти потоки не выполняют блокирующие вызовы, то подойдет простой атомарный флаг с периодическими проверками. В противном случае вам нужен способ разорвать блокирующий вызов. Если это вызов ввода-вывода, введите еще один канал уведомлений. Если он блокирует переменную условия, используйте std::condition_variable::notify_all().

person Joseph Artsimovich    schedule 16.06.2017
comment
Проверьте образцы кода boost.asio: boost.org/doc/libs/1_64_0/doc/html/boost_asio/example/cpp11/ - person Michaël Roy; 16.06.2017
comment
@Tulon Не могли бы вы показать мне в коде, как это будет выглядеть, пожалуйста? Я не могу использовать сторонние библиотеки - person djent; 16.06.2017
comment
@djent Я объяснил, как это делается в принципе, но реализация зависит от вас. - person Joseph Artsimovich; 16.06.2017