C中的线程同步和条件变量问题
我有三个线程,一个是主线程,另外两个是辅助线程。当有工作要做时,第一个线程唤醒两个线程中的一个。每一个线程在被唤醒时都会执行一些计算,如果它发现有更多的工作要做,则可以唤醒另一个工作线程,或者干脆决定自己做这项工作(例如,通过将工作添加到本地队列)。 当工作线程有工作要做时,主线程必须等待工作完成。我用以下条件变量实现了这一点(这里报告的代码隐藏了很多细节,请询问是否有不可理解的地方): 主线程(伪代码): 工作线程:C中的线程同步和条件变量问题,c,multithreading,synchronization,pthreads,C,Multithreading,Synchronization,Pthreads,我有三个线程,一个是主线程,另外两个是辅助线程。当有工作要做时,第一个线程唤醒两个线程中的一个。每一个线程在被唤醒时都会执行一些计算,如果它发现有更多的工作要做,则可以唤醒另一个工作线程,或者干脆决定自己做这项工作(例如,通过将工作添加到本地队列)。 当工作线程有工作要做时,主线程必须等待工作完成。我用以下条件变量实现了这一点(这里报告的代码隐藏了很多细节,请询问是否有不可理解的地方): 主线程(伪代码): 工作线程: while (1){ pthread_mutex_lock(&
while (1){
pthread_mutex_lock(&main_lock);
if (work == 0)
pthread_cond_signal(&main_cond);
pthread_mutex_unlock(&main_lock);
//code to let the worker thread wait again -- PROBLEM!
while (I have work to do, in my queue){
do_work()
}
}
问题是:当一个工作线程唤醒主线程时,我不确定该工作线程是否调用了wait以使自己处于等待新工作的状态。即使我用另一个条件变量来实现这个等待,也可能发生主线程是唤醒的,在到达某个点之前会做一些工作,在该点上他必须唤醒尚未调用等待的线程。。。这可能会导致糟糕的结果。我已经尝试了几种方法来解决这个问题,但我找不到解决方案,也许有一种明显的方法可以解决它,但我错过了
你能提供一个解决这类问题的方案吗?我使用的是C语言,我可以使用您认为合适的任何同步机制,比如pthreads或posix信号量
谢谢您能拥有由主线程管理的“新作业”队列吗?主线程一次可以向每个工作线程分发一个作业。主线程还将监听工人完成的作业。如果工作线程发现需要执行的新作业,只需将其添加到“新作业”队列中,主线程就会分发它
伪代码:
//this function can be called from the main several time. It blocks the main thread till the work is done.
void new_work(){
//signaling to worker threads if work is available
//Now, the threads have been awakened, it's time to sleep till they have finished.
pthread_mutex_lock(&main_lock);
while (work > 0) //work is a shared atomic integer, incremented each time there's work to do and decremented when finished executing some work unit
pthread_cond_wait(&main_cond);
pthread_mutex_unlock(&main_lock);
}
JobQueue NewJobs;
Job JobForWorker[NUM_WORKERS];
workerthread()
{
while(wait for new job)
{
do job (this may include adding new jobs to NewJobs queue)
signal job complete to main thread
}
}
main thread()
{
while(whatever)
{
wait for job completion on any worker thread
now a worker thread is free put a new job on it
}
}
您是否可以拥有由主线程管理的“新作业”队列?主线程一次可以向每个工作线程分发一个作业。主线程还将监听工人完成的作业。如果工作线程发现需要执行的新作业,只需将其添加到“新作业”队列中,主线程就会分发它
伪代码:
//this function can be called from the main several time. It blocks the main thread till the work is done.
void new_work(){
//signaling to worker threads if work is available
//Now, the threads have been awakened, it's time to sleep till they have finished.
pthread_mutex_lock(&main_lock);
while (work > 0) //work is a shared atomic integer, incremented each time there's work to do and decremented when finished executing some work unit
pthread_cond_wait(&main_cond);
pthread_mutex_unlock(&main_lock);
}
JobQueue NewJobs;
Job JobForWorker[NUM_WORKERS];
workerthread()
{
while(wait for new job)
{
do job (this may include adding new jobs to NewJobs queue)
signal job complete to main thread
}
}
main thread()
{
while(whatever)
{
wait for job completion on any worker thread
now a worker thread is free put a new job on it
}
}
我相信你在这里看到的是。您正在做的是编写一个计数信号量的特殊实现(一个用于提供不只是互斥的信号量) 如果我没有看错你的问题,你要做的是让工作线程阻塞,直到有一个工作单元可用,然后在它可用时执行一个工作单元。您的问题在于有太多的可用工作,而主线程试图取消阻止已在工作的工作线程。我将按如下方式构造您的代码
sem_t main_sem;
sem_init(&main_sem, 0, 0);
void new_work() {
sem_post(&main_sem);
pthread_cond_wait(&main_cond);
}
void do_work() {
while (1) {
sem_wait(&main_sem);
// do stuff
// do more stuff
pthread_cond_signal(&main_sem);
}
}
现在,如果工作线程生成更多的工作,那么它们可以简单地sem\u post
到信号量,并简单地延迟pthread\u cond\u信号
,直到所有工作完成
但是,请注意,如果您确实需要在辅助线程工作时始终阻止主线程,那么当您可以调用执行该工作的函数时,将该工作推送到另一个线程是没有用的。我相信您在这里看到的是。您正在做的是编写一个计数信号量的特殊实现(一个用于提供不只是互斥的信号量) 如果我没有看错你的问题,你要做的是让工作线程阻塞,直到有一个工作单元可用,然后在它可用时执行一个工作单元。您的问题在于有太多的可用工作,而主线程试图取消阻止已在工作的工作线程。我将按如下方式构造您的代码
sem_t main_sem;
sem_init(&main_sem, 0, 0);
void new_work() {
sem_post(&main_sem);
pthread_cond_wait(&main_cond);
}
void do_work() {
while (1) {
sem_wait(&main_sem);
// do stuff
// do more stuff
pthread_cond_signal(&main_sem);
}
}
现在,如果工作线程生成更多的工作,那么它们可以简单地sem\u post
到信号量,并简单地延迟pthread\u cond\u信号
,直到所有工作完成
但是请注意,如果您确实需要在辅助线程工作时始终阻止主线程,那么当您可以只调用执行该工作的函数时,将该工作推送到另一个线程是没有用的。如果您希望主线程将工作分配给其他两个线程,那么请等到两个线程都完成工作后再继续,你可以用一个屏障来完成这项工作 屏障是一种同步构造,您可以使用它使线程在代码中的某个点等待,直到设置数量的线程都准备好继续。本质上,您初始化一个pthread屏障,即在允许任何线程继续之前,必须有x个线程等待它。当每个线程完成其工作并准备继续时,它将在屏障上等待,一旦x个线程到达屏障,它们都可以继续 在您的情况下,您可能可以执行以下操作:
pthread_barrier_t barrier;
pthread_barrier_init(&barrier, 3);
master()
{
while (work_to_do) {
put_work_on_worker_queues();
pthread_barrier_wait(&barrier);
}
}
worker()
{
while(1) {
while (work_on_my_queue()) {
do_work();
}
pthread_barrier_wait(&barrier);
}
}
这将使主线程发出工作,然后等待两个工作线程完成它们所完成的工作(如果有的话),然后再继续。如果希望主线程将工作分配给其他两个线程,然后等待两个线程完成其工作,然后再继续,您可以使用屏障来完成这项工作 屏障是一种同步构造,您可以使用它使线程在代码中的某个点等待,直到设置数量的线程都准备好继续。本质上,您初始化一个pthread屏障,即在允许任何线程继续之前,必须有x个线程等待它。当每个线程完成其工作并准备继续时,它将在屏障上等待,一旦x个线程到达屏障,它们都可以继续 在您的情况下,您可能可以执行以下操作:
pthread_barrier_t barrier;
pthread_barrier_init(&barrier, 3);
master()
{
while (work_to_do) {
put_work_on_worker_queues();
pthread_barrier_wait(&barrier);
}
}
worker()
{
while(1) {
while (work_on_my_queue()) {
do_work();
}
pthread_barrier_wait(&barrier);
}
}
这将使主线程完成工作,然后等待两个工作线程在之前完成它们所完成的工作(如果有的话)