pthread_cond_wait 和 pthread_mutex_lock 没有按预期工作
pthread_cond_wait and pthread_mutex_lock doesnt work as expected
我创建了一个 ThreadPool class,还有一个名为 execute_thread_helper()
的无效函数,它在 void* execute_thread(void* arg)
内部被调用(它是一个以这种方式提供给线程的函数:ret = pthread_create(&workers[i], NULL, execute_thread, (void*)this);
)
void ThreadPool::execute_thread_helper()
{
Task task;
pthread_mutex_lock(&mutex);
while(TaskList.empty()) // Previously "if"
{
cout << "Thread #" << pthread_self() << " is blocked. "<< endl;
pthread_cond_wait(&conditionVar, &mutex);
}
task = TaskList.front();
TaskList.pop();
cout << "Thread #" << pthread_self() << " going to run the function. "<< endl;
threadFunction(task);
pthread_mutex_unlock(&mutex);
}
任务以这种方式添加到任务队列中 -
void ThreadPool::add_task(Task newTask)
{
pthread_mutex_lock(&mutex);
TaskList.push(newTask);
pthread_cond_signal(&conditionVar);
pthread_mutex_unlock(&mutex);
}
据我了解,一旦创建线程 - 它就会尝试 运行 execute_thread
。然后,给定一个空队列,我希望 pthread_cond_wait
"put" 线程休眠(并对所有创建的线程执行此操作)直到它被 add_task
中的 pthread_cond_signal
唤醒.
好吧..我尝试在单个线程上检查程序,并得到了这个结果(我还没有 add_task
。只是尝试创建池)-
Thread #139859560904448 is blocked.
Thread #139859560904448 going to run the function.
in map() key is and value is 0
我不明白线程是如何通过 if 语句的,如果它之前被搁置的话。
尝试创建 3 个线程池时的输出 -
Thread #140013458028288 is blocked.
Thread #140013458028288 going to run the function.
in map() key is and value is 0
Thread #140013458028288 going to run the function.
in map() key is and value is 0
Thread #140013458028288 going to run the function.
in map() key is and value is 0
为什么其他 2 个话题没有被搁置?
编辑
感谢 SergeyA,将 if 与 while 切换,确实有所帮助。
但是,仍然尝试创建 3 个线程池,结果是 -
Thread #139916558706432 is blocked.
Thread #139916558706432 is blocked.
Thread #139916558706432 is blocked.
Thread #139916558706432 is blocked.
Thread #139916558706432 is blocked.
Thread #139916558706432 is blocked.
Thread #139916558706432 is blocked.
Thread #139916558706432 is blocked.
为什么没有创建其他线程?它们不是都应该被创建,运行 同时交替打印它们被阻止吗?
条件变量容易出现所谓的 *spurios 唤醒。这意味着代码已解锁,但条件并没有真正改变,也没有发出信号。
这就是为什么你总是要循环调用wait
函数,并在每次唤醒后检查条件。
pthread_cond_signal(&conditionVar);
只会唤醒 一个 等待线程。如果您的任务足够短,您将偶然总是唤醒同一个线程。没有公平。 :-)
您还可以使用pthread_cond_broadcast(&conditionVar);
唤醒所有等待的线程。然后你应该看到你所有的线程总是被唤醒。但是对于你的线程池来说,应该没有必要使用广播变体。
我创建了一个 ThreadPool class,还有一个名为 execute_thread_helper()
的无效函数,它在 void* execute_thread(void* arg)
内部被调用(它是一个以这种方式提供给线程的函数:ret = pthread_create(&workers[i], NULL, execute_thread, (void*)this);
)
void ThreadPool::execute_thread_helper()
{
Task task;
pthread_mutex_lock(&mutex);
while(TaskList.empty()) // Previously "if"
{
cout << "Thread #" << pthread_self() << " is blocked. "<< endl;
pthread_cond_wait(&conditionVar, &mutex);
}
task = TaskList.front();
TaskList.pop();
cout << "Thread #" << pthread_self() << " going to run the function. "<< endl;
threadFunction(task);
pthread_mutex_unlock(&mutex);
}
任务以这种方式添加到任务队列中 -
void ThreadPool::add_task(Task newTask)
{
pthread_mutex_lock(&mutex);
TaskList.push(newTask);
pthread_cond_signal(&conditionVar);
pthread_mutex_unlock(&mutex);
}
据我了解,一旦创建线程 - 它就会尝试 运行 execute_thread
。然后,给定一个空队列,我希望 pthread_cond_wait
"put" 线程休眠(并对所有创建的线程执行此操作)直到它被 add_task
中的 pthread_cond_signal
唤醒.
好吧..我尝试在单个线程上检查程序,并得到了这个结果(我还没有 add_task
。只是尝试创建池)-
Thread #139859560904448 is blocked.
Thread #139859560904448 going to run the function.
in map() key is and value is 0
我不明白线程是如何通过 if 语句的,如果它之前被搁置的话。
尝试创建 3 个线程池时的输出 -
Thread #140013458028288 is blocked.
Thread #140013458028288 going to run the function.
in map() key is and value is 0
Thread #140013458028288 going to run the function.
in map() key is and value is 0
Thread #140013458028288 going to run the function.
in map() key is and value is 0
为什么其他 2 个话题没有被搁置?
编辑
感谢 SergeyA,将 if 与 while 切换,确实有所帮助。 但是,仍然尝试创建 3 个线程池,结果是 -
Thread #139916558706432 is blocked.
Thread #139916558706432 is blocked.
Thread #139916558706432 is blocked.
Thread #139916558706432 is blocked.
Thread #139916558706432 is blocked.
Thread #139916558706432 is blocked.
Thread #139916558706432 is blocked.
Thread #139916558706432 is blocked.
为什么没有创建其他线程?它们不是都应该被创建,运行 同时交替打印它们被阻止吗?
条件变量容易出现所谓的 *spurios 唤醒。这意味着代码已解锁,但条件并没有真正改变,也没有发出信号。
这就是为什么你总是要循环调用wait
函数,并在每次唤醒后检查条件。
pthread_cond_signal(&conditionVar);
只会唤醒 一个 等待线程。如果您的任务足够短,您将偶然总是唤醒同一个线程。没有公平。 :-)
您还可以使用pthread_cond_broadcast(&conditionVar);
唤醒所有等待的线程。然后你应该看到你所有的线程总是被唤醒。但是对于你的线程池来说,应该没有必要使用广播变体。