Как сигнализировать рабочим потокам, что есть работа, которую нужно закончить? - PullRequest
0 голосов
/ 02 февраля 2020

Я строю небольшой сокет-сервер, на котором я хочу создать пул потоков, а затем работать в паттерне потоков начальник-рабочий. Таким образом, всякий раз, когда запрос (главный) получает запрос, он передается одному из рабочих потоков из пула.

В следующем фрагменте я пытаюсь создать 10 потоков.

void* process_data(void* arg) {
    printf("invoked by the created thread");
    while(1) {
          // sleep until woken
          // get item from queue
          // do something
    }
}

int total_threads_to_create = 10;
int total_created = 0;
while(total_created < 10) {
   // create 10 threads
   pthread_t thread;
   int created = pthread_create(&thread, NULL, process_data, NULL);
   if(created == 0) total_created++;
}

while(1) {
   // server accepts the request in an infinite loop
   int socket_fd = accept(ss_fd, (struct sockaddr*)&client_sock,&client_sock_len);

   put_new_request_in_queue();
   // signal to one of the thread that work is available

}

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

Как мне:

  • заставить поток внутри process_data спать до тех пор, пока он не разбудил основной поток?
  • как я могу сообщить рабочему потоку, что существует запрос на обслуживание?

Ответы [ 2 ]

1 голос
/ 02 февраля 2020

Нормальным решением является условная переменная и очередь. Общий шаблон здесь называется шаблоном производитель / потребитель.

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

Производитель :

workToDo = generateSomeWork()
acquire mutex
queue.push(workToDo)
cv.notify();
release mutex

Потребитель :

loop:
    acquire mutex
    while queue empty
        wait on cv (releasing mutex while waiting)
    workToDo = queue.pop()
    release mutex
    do(workToDo)

Лично я также хотел бы добавить логический флаг done, который установлен в True, когда его время для всех рабочих убирать. Таким образом, когда вы хотите аккуратно выйти из программы, вы приобретаете мьютекс, устанавливаете done на true, а затем транслируете на cv, что пробуждает все работы. Они видят, что done установлен, и полностью завершаются.

0 голосов
/ 02 февраля 2020

У вас есть производитель-потребитель, вы используете семафор

Вы написали пример "проблемы производителя-потребителя" .

Наиболее подходящим механизмом управления для очереди производителя-потребителя является использование семафора .

Вам также необходимо заблокировать общую очередь

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

Статья Wikipedia для Producer-Consumer содержит общее решение для вас, но не использует точно такие же имена функций, что и в используемой вами библиотеке pthreads.

Реализация семафора Pthreads

Библиотека pthreads реализует семафоры через типы sem_t и sem_wait() ("wait") и sem_post() ("сигнал") звонков.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...