pthreads:一个触发其他线程的线程

5
你好, 我是多线程编程的新手。 我正在尝试创建一个代码,创建一个名为THREAD1的线程,在完成某些操作后,触发其他两个线程THREAD2和THREAD3,然后退出。
我写了两种可能的解决方案。
1)使用条件变量(不起作用:在某些情况下会出现死锁):
pthread_mutex_t ready_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t  ready_cond  = PTHREAD_COND_INITIALIZER;
bool ready = false;

void* trigger(void*);
void* func1(void*);
void* func2(void*);

int main()
{
    pthread_t thread1;
    pthread_t thread2;
    pthread_t thread3;  
    pthread_create(&thread1, 0, &trigger, 0);
    pthread_create(&thread2, 0, &func1, 0);
    pthread_create(&thread3, 0, &func2, 0);
    pthread_join(thread1, 0);
    pthread_join(thread2, 0);
    pthread_join(thread3, 0);
}

void *trigger(void*)
{
    pthread_mutex_lock(&ready_mutex);
    ready = true;
    pthread_cond_broadcast(&ready_cond);
    pthread_mutex_unlock(&ready_mutex);
    return 0;
}

void *func1(void*)
{
    while (!ready) // Needed to avoid spuriuos wake-up
    {
        pthread_mutex_lock(&ready_mutex);
        pthread_cond_wait(&ready_cond, &ready_mutex);
        pthread_mutex_unlock(&ready_mutex);
    }
    std::cout << "In 'func1'>> Do something" << std::endl;
    return 0;
}

void *func2(void*)
{
    while (!ready) // Needed to avoid spuriuos wake-up
    {
        pthread_mutex_lock(&ready_mutex);
        pthread_cond_wait(&ready_cond, &ready_mutex);
        pthread_mutex_unlock(&ready_mutex);
    }
    std::cout << "In 'func2'>> Do something" << std::endl;
    return 0;
}

2) THREAD1 直接创建另外两个线程。

pthread_mutex_t ready_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t  ready_cond  = PTHREAD_COND_INITIALIZER;

pthread_t thread1;
pthread_t thread2;
pthread_t thread3;

void* trigger(void*);
void* func1(void*);
void* func2(void*);

int main()
{
    pthread_create(&thread1, 0, &trigger, 0);

    pthread_join(thread1, 0);
    pthread_join(thread2, 0);
    pthread_join(thread3, 0);
}

void *trigger(void*)
{
    std::cout << "In 'trigger'>> Do something" << std::endl;

    pthread_create(&thread2, 0, &func1, 0);
    pthread_create(&thread3, 0, &func2, 0);

    return 0;
}

void *func1(void*)
{
    std::cout << "In 'func1'>> Do something" << std::endl;

    return 0;
}

void *func2(void*)
{
    std::cout << "In 'func2'>> Do something" << std::endl;

    return 0;
}

我想知道您的意见。

非常感谢。


你的第二个实现似乎运行良好,你认为有什么问题吗? - engineerC
你的第二个选项更清晰、更优美。我会选择它。 - Rafael Baptista
@CaptainMurphy:我只是想知道是否有更好的方法来达到这个目标。从POSIX手册页面上看,似乎条件变量更适合这个目的,因为它们可以用于发出特定事件的信号。 - seg.fault
你的“虚假唤醒”循环不太对:你需要先锁定,然后 while (!read) cond_wait(),最后解锁。现在你检查一个互斥保护的变量 (ready) 的值,而没有先锁住互斥体——这样不好。 - pilcrow
@pilcrow:是的,我知道。Maxim Yegorushkin已经指出了这一点(请参见下面的第一个答案)。谢谢。 - seg.fault
1个回答

5

使用条件变量(存在问题:在某些情况下会出现死锁):

当检查共享变量ready的状态时,代码并未锁定互斥锁。当它锁定互斥锁ready可能已经在那个时候改变了,这就是为什么会出现死锁的原因。

等待状态改变正确的版本应该使用条件变量(错误检查被省略):

pthread_mutex_lock(&ready_mutex);
while(!ready) // Needed to avoid spuriuos wake-up
    pthread_cond_wait(&ready_cond, &ready_mutex);
// ready == true here
pthread_mutex_unlock(&ready_mutex);

以上假设只有在持有相同的互斥锁时才会更改ready

是的,你说得对。那么,回到我的问题,我应该使用条件变量(解决方案#1)还是延迟线程创建(解决方案#2)? - seg.fault
1
@seg.fault 我会使用奥卡姆剃刀原理:在多个问题解决方案中选择更简单的一个。 - Maxim Egorushkin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接