Posix pthread рабочий, который работает только при необходимости
У меня есть рабочий поток, выполняющий опрос (он нацелен на libcurl, но это не имеет значения).
Многие действия из приложения могут запустить рабочий поток, но если он уже запущен, новый поток создавать не следует. Новый запрос от приложения просто объединяется с любым другим уже проводимым опросом.
Таким образом, один рабочий поток, который завершается, когда больше нечего делать.
Код является:
pthread_t thread = NULL;
struct timespec sleep_val = {0, 20000000};
void *worker_thread(void *threadid)
{
do {
poll();
nanosleep(&sleep_val, NULL);
} while (no_of_handles_running > 0);
pthread_exit(NULL);
thread = NULL;
}
void start_worker_thread_if_needed() {
if (thread == NULL) {
pthread_create(&thread, NULL, worker_thread, NULL);
}
}
Я сомневаюсь в безопасности потоков. Функция start_worker_thread_if_needed() может быть вызвана в любое время любое количество раз.
Итак, что если start_worker_thread_if_needed() вызывается именно тогда, когда мы выходим из цикла while и поэтому прерываем рабочий поток. Если это произойдет, условие if (thread == NULL) будет FALSE, так как рабочий поток прерван, а pthread_exit + thread = NULL еще не завершен.
Так что теперь start_worker_thread_if_needed() выйдет без создания нового потока, но как только управление вернется к старому рабочему потоку, оно перейдет к строке pthread_exit и рабочий поток будет уничтожен.
Проблема будет в том, что запрос, который был только что сделан, вызывая start_worker_thread_if_needed(), будет потерян, и опрос не начнется до следующего вызова start_worker_thread_if_needed().
Изменить: Вот предложение с мьютексом, но у меня все еще есть те же сомнения. Что произойдет, если основной поток прервется сразу после того, как мы выйдем из цикла while и до того, как рабочий сможет взять мьютекс. Тогда основной поток не создает новый поток, а затем рабочий выход.
void *worker_thread(void *threadid)
{
do {
poll();
nanosleep(&sleep_val, NULL);
} while (no_of_handles_running > 0);
pthread_mutex_lock(&my_mutex);
thread = NULL;
pthread_mutex_unlock(&my_mutex);
pthread_exit(NULL);
}
void start_worker_thread_if_needed() {
pthread_mutex_lock(&my_mutex);
if (thread == NULL) {
pthread_create(&thread, NULL, worker_thread, NULL);
}
pthread_mutex_unlock(&my_mutex);
}
Я думаю, что у меня есть недостаток в том, как я это настроил, и я был бы очень признателен, если бы кто-то мог помочь с правильным решением.
1 ответ
Спасибо за помощь в комментариях выше. Предложение Кейлумса использовать условные переменные, похоже, является хорошим подходом, чтобы не рисковать, заканчивая тем угловым случаем, который меня беспокоил.
Окончательный код (с удаленными журналами) приведен ниже и работает нормально.
static int no_of_handles_running;
static int RUN_THREAD = 0;
pthread_t thread = NULL;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cv = PTHREAD_COND_INITIALIZER;;
void *worker_thread(void *threadid)
{
RUN_THREAD = 1;
do {
poll(); //Will update no_of_handles_running
if (no_of_handles_running == 0) {
pthread_mutex_lock(&mutex);
pthread_cond_wait(&cv, &mutex);
pthread_mutex_unlock(&mutex);
}
} while (RUN_THREAD);
thread = NULL;
pthread_exit(NULL);
}
void start_worker_thread() {
if (thread == NULL) {
int rc = pthread_create(&thread, NULL, worker_thread, NULL);
if (rc){
return;
}
}
pthread_mutex_lock(&mutex);
pthread_cond_signal(&cv);
pthread_mutex_unlock(&mutex);
}
void stop_worker_thread() {
RUN_THREAD = 0;
pthread_mutex_lock(&mutex);
pthread_cond_signal(&cv);
pthread_mutex_unlock(&mutex);
}