【问题标题】:Scheduling of Multiple Threads using Mutex and Condition Variable使用互斥锁和条件变量调度多线程
【发布时间】:2015-03-26 11:02:02
【问题描述】:

我正在尝试创建四个线程来打印一些消息。
我遇到了一些同步问题。

这是我的main() 的样子

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;    
pthread_cond_t  cond  = PTHREAD_COND_INITIALIZER; 
int count = 4;

int main (void)
{
    pthread_t thread1, thread2, thread3, thread4;
    pthread_create (&thread4, NULL, function4, NULL);
    pthread_create (&thread3, NULL, function3, NULL);
    pthread_create (&thread2, NULL, function2, NULL);
    pthread_create (&thread1, NULL, function1, NULL);

    pthread_join (thread1, NULL);
    pthread_join (thread2, NULL);
    pthread_join (thread3, NULL);
    pthread_join (thread4, NULL);
    return 0;                                                                   
}

function1() 打印 Function 1function2() 打印 Function 2 等等。

所需的输出应如下所示:

Function 1   
Function 2  
Function 3  
Function 4

实际输出:

Function 1
/* Infinitely runs (Deadlock maybe) */

实际问题
我们可以使用一个条件变量来同步两个或多个线程吗?如果有怎么办?

如果没有,我该如何解决这个问题?


这里是function(n)的定义

void *function1 ()
{
    while (1)
    {
    if (count == 4)
        {
            pthread_mutex_lock (&mutex);
            printf("Function 1\n");
            count --;
            pthread_mutex_unlock (&mutex);
            pthread_cond_signal (&cond);
            return NULL;
        }
      else
          pthread_cond_wait(&cond, &mutex);
    }
    return NULL;
}

void *function2 ()
{
while (1)
    {
        if (count == 3)                                                         
        {
            pthread_mutex_lock (&mutex);
            printf("Function 2\n");
            count--;
            pthread_mutex_unlock (&mutex);
            pthread_cond_signal (&cond);                                        
            return NULL;
        }
        else                                                                    
            pthread_cond_wait(&cond, &mutex);        
    }
    return NULL;
}

void *function3 ()
{
    while (1)
    {
        if(count == 2)
        {
            pthread_mutex_lock (&mutex);
            printf("Function 3\n");
            count--;
            pthread_mutex_unlock (&mutex);
            pthread_cond_signal (&cond);
            return NULL;
        }
        else
            pthread_cond_wait(&cond, &mutex);      
    }
    return NULL;
}

void *function4 ()
{
    while (1)
    {
        if(count == 1)
        {
            pthread_mutex_lock (&mutex);
            printf("Function 4\n");
            pthread_mutex_unlock (&mutex);
            pthread_cond_signal (&cond);
            return NULL;
        }
        else
            pthread_cond_wait(&cond, &mutex);
    }
    return NULL;
}

【问题讨论】:

  • 请注意,您应该使用pthread_cond_wait 同时持有互斥锁。

标签: c multithreading synchronization mutex condition-variable


【解决方案1】:

经过更清晰的了解,我已经解决了这个问题。
这是一种竞争条件。

代码有问题:

  1. 使用pthread_cond_broadcast 代替pthread_cond_signal
    来自man 页面

    pthread_cond_broadcast() 函数将解除阻塞当前在指定条件变量 cond 上阻塞的所有线程。

    pthread_cond_signal() 函数应至少解除阻塞在指定条件变量 cond 上阻塞的线程之一

  2. 在检查 if (count == X) 之前未获取 lock,需要 在此之前放置一个锁(因为count 是全局/共享变量)。

  3. 如果控件转到else,则不放置unlock。自从有了锁 已经放置(早于else),您需要unlock 它。

    如果你不这样做,其他线程会尝试lock一个互斥锁, 那已经被锁定,导致竞争条件。


功能如下

void *function1 ()
{
    while (1)
    {
        /* Take a lock on the Mutex */
        pthread_mutex_lock (&mutex);
        if (4 == count)
        {
            printf("Function 1\n");    /* Perform your task */
            count--;
            /* Once operation on shared variable (count) is completed, release lock*/
            pthread_mutex_unlock (&mutex);

            /* Broadcast to other threads about completion of task */
            pthread_cond_broadcast (&cond);
            return NULL;
        }
        else 
        { 
            /* If count doesnt match, wait on the condition (wait for signal from other threads) */
            pthread_cond_wait(&cond, &mutex);   
            /* Unlock the mutex, since it was locked earlier - else goes to deadlock */
            pthread_mutex_unlock (&mutex);
        }
    }
    return NULL;
}

Here 是完整的工作代码。

【讨论】:

    【解决方案2】:

    所需的更改很简单:

    代替:

    else
        pthread_cond_wait(&cond, &mutex);
    

    这样做:

    else {
        pthread_mutex_lock (&mutex);
        pthread_cond_wait(&cond, &mutex);
        pthread_mutex_unlock (&mutex);
    }
    

    这些更改对我有用,但如果没有更改,则会导致不可预测的行为。

    编辑:

    上面提到的这种简单方法仍然会留下竞争条件,并且不能解决 signalbroadcast 的问题。为避免这种情况,代码的结构应如下所示:

    pthread_mutex_lock (&mutex);
    if (count == 4)
    {
        printf("Function 1\n");
        count --;
        pthread_mutex_unlock (&mutex);
        pthread_cond_broadcast (&cond); // NOTE: broadcast, not signal!
        return NULL;
     }
    else
        pthread_cond_wait(&cond, &mutex);
    pthread_mutex_unlock (&mutex);
    

    请注意,pthread_cond_broadcast 是必需的,因为您想唤醒所有线程。

    【讨论】:

    • 以上更改给了我相同的结果,没有变化。
    • 是的,确实如此。注意最后的编辑。它修复了竞争条件并使用广播而不是在这个用例中真正需要的信号。我设法偶尔重现了这个问题,现在它总是对我有用。
    • 谢谢,我只能看到来自function1function2 的打印件,其余部分看不到。这是我使用的确切代码 paste.ubuntu.com/10683407 。我将同时调查pthread_cond_broadcast
    猜你喜欢
    • 2015-09-14
    • 2018-03-05
    • 2015-06-19
    • 1970-01-01
    • 2013-12-15
    • 2010-11-06
    • 2018-03-09
    • 2023-03-10
    • 2018-10-06
    相关资源
    最近更新 更多