【问题标题】:Associate global value with signal将全局价值与信号联系起来
【发布时间】:2011-10-27 10:05:12
【问题描述】:

我的意图是让 send() 在全局计数器为奇数时忽略信号,并在偶数时广播。然后有 2 个 recv() 线程,等待信号。在信号的情况下,只有一个 recv() 线程可以接收它;在广播的情况下,双方都可以收到。

但我的结果显示两个 recv() 都收到了相同的奇数,这不应该发生。

我的代码中的全局计数器和信号是否紧密耦合?

编辑:

我想我得到了这个问题的答案。 recv() 线程收到信号后,会再次尝试锁定与条件变量关联的互斥锁,但可能需要等待,因为互斥锁可能已经被其他线程锁定。在等待期间,全局计数可能会发生变化,因此它最终打印的全局计数与收到信号时的不同。

另外,在我的代码中,即使 send() 发送广播,多个 recv() 线程实际上也不能同时处理信号,因为它们仍然是互斥的,因为它们共享同一个互斥锁

编辑结束

#include <pthread.h>
#include <stdio.h>

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

int n = 0;
int count = 0;

void* recv(void *name)
{
    while(1)
    {
        pthread_mutex_lock(&mutex);

        // wait for signal
        pthread_cond_wait(&cond, &mutex);
        count++;

        if(count > 10)
        {
            printf("number %d terminate %s\n", n, (char*)name);
        }
        else
        {
            printf("%s gets number:%d\n", (char*)name, n);
        }
        pthread_mutex_unlock(&mutex);

        if(count > 10)
        {
            return (NULL);
        }
    }
}

void* send(void *ptr)
{
    while(1)
    {
        pthread_mutex_lock(&mutex);
        n++;
        //  odd: signal
        // even: broadcast
        if(n%2)
            pthread_cond_signal(&cond);
        else
            pthread_cond_broadcast(&cond);
        pthread_mutex_unlock(&mutex);
    }
}


int main(int argc, char *argv[])
{    
    pthread_t t1, t2, t3;

    char *name1 = "t1";
    char *name2 = "t2";

    pthread_create(&t1, NULL, recv, (void *) name1);
    pthread_create(&t2, NULL, recv, (void *) name2);
    pthread_create(&t3, NULL, send, NULL);

    pthread_join(t1, NULL);
        pthread_join(t2, NULL);

    pthread_cancel(t3);

    return 0;
}

输出,注意前两行:

t2 gets number:12493
t1 gets number:12493
t1 gets number:12534
t2 gets number:12534
t1 gets number:12623
t1 gets number:12624
t2 gets number:12666
t1 gets number:12666
t2 gets number:12713
t1 gets number:12713
number 12770 terminate t2
number 12998 terminate t1

【问题讨论】:

    标签: c synchronization pthreads


    【解决方案1】:

    广播唤醒后,不能保证线程会被调度为:

    t1
    t2
    t3
    

    t2
    t1
    t3
    

    你完全有可能得到:

    t1
    t3
    t2
    

    ...其中 t3 将 n 递增到奇数并唤醒 t1,然后 t2 和 t1 都打印该奇数。

    如果你想像这样紧密地联锁执行,你需要引入更多的同步。

    【讨论】:

    • 即使使用 t3(唤醒)- t1 - t2 - t3 的时间表,这里也完全有可能得到错误的结果。代码的核心问题是 t1 和 t2 在收到信号并获得互斥体后打印 n 的值,而不是在发送信号时。 t3 在其第一个时间片内将增加 n 次。
    • @thiton:是的,这取决于你实际得到的调度算法。
    【解决方案2】:

    您看到此结果的原因是因为您正在增加send() 中的全局n 变量。如果你在recv() 中增加它,你会看到不同的结果。原因是每个线程分别接收广播或信号,一个接一个,并打印结果,但每个recv只发生一次发送。

    如果你想看到它在每个线程的基础上计数,你应该在recv()的锁内增加一个变量

    顺便说一下,这些是其他 c 函数的名称。您可能应该选择其他的。

    【讨论】:

      【解决方案3】:

      信号/广播函数异步工作:send() 不会在它发出信号的那一刻放弃控制,而是在它的循环中循环直到它的时间片结束。在 send() 的时间片中,t1 和 t2 都被唤醒了很多次,所以都打印了值。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2019-06-20
        • 1970-01-01
        • 2018-06-21
        • 2012-04-09
        • 2021-05-27
        • 2011-01-25
        • 1970-01-01
        相关资源
        最近更新 更多