Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 使用条件变量多线程时出现意外行为_C_Multithreading_Mutex_Condition Variable - Fatal编程技术网

C 使用条件变量多线程时出现意外行为

C 使用条件变量多线程时出现意外行为,c,multithreading,mutex,condition-variable,C,Multithreading,Mutex,Condition Variable,在下面的代码中: #include <stdio.h> #include <pthread.h> pthread_mutex_t mtx; pthread_cond_t cond; int how_many = 10; int pool = 0; void * producer(void * ptr) { while (how_many > 0) { pthread_mutex_lock(&

在下面的代码中:

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

pthread_mutex_t mtx;
pthread_cond_t cond;

int how_many = 10;
int pool = 0;

void * producer(void * ptr)
{
        while (how_many > 0)
        {
                pthread_mutex_lock(&mtx);
                printf("producer: %d\n", how_many);
                pool = how_many;
                how_many--;
                pthread_mutex_unlock(&mtx);
                pthread_cond_signal(&cond);
        }

        pthread_exit(0);
}

void * consumer(void * ptr)
{
        while (how_many > 0)
        {
                pthread_mutex_lock(&mtx);
                pthread_cond_wait(&cond, &mtx);
                printf("consumer: %d\n", pool);
                pool = 0;
                pthread_mutex_unlock(&mtx);
        }
        pthread_exit(0);
}

int main(int argc, char ** argv)
{
        pthread_t prod, cons;
        pthread_mutex_init(&mtx, 0);
        pthread_cond_init(&cond, 0);
        pthread_create(&cons, 0, consumer, 0);
        pthread_create(&prod, 0, producer, 0);
        pthread_join(prod, 0);
        pthread_join(cons, 0);
        pthread_cond_destroy(&cond);
        pthread_mutex_destroy(&mtx);
        return 0;
}
实际输出:

Producer:10    
Consumer:10    
Producer:9    
Consumer:9    
Producer:8    
Consumer:8    
Producer:7    
Consumer:7    
Producer:6    
Consumer:6    
Producer:5    
Consumer:5    
Producer:4    
Consumer:4    
Producer:3    
Consumer:3    
Producer:2    
Consumer:2    
Producer:1    
Consumer:1
producer: 10    
producer: 9    
producer: 8    
producer: 7    
producer: 6    
producer: 5    
producer: 4    
producer: 3    
producer: 2    
producer: 1
另外,在消费者方面,如果我们锁定并等待信号,生产者如何获得锁定,以便能够将信号发送给消费者

  • 会是死锁吗
  • 我的朋友建议像
    pthread\u cond\u wait(&cond,&mtx)
    ;实际上会解锁资源,直到它从生产者那里得到信号。这是真的吗

  • 您正在检查锁定部分的数量。您需要重新构造代码,以使读取变量被锁覆盖,或使其为C11


    即使如此,代码的输出也可能不是您想要的方式,因为线程的调度非常不可预测。

    对于预期的输出,您可以使用如下锁定机制

     #include <pthread.h> 
     #include <stdio.h> 
     #include <stdlib.h> 
     #include <semaphore.h> 
    
     sem_t mutex1; 
     sem_t mutex2; 
     int main()
     {
        pthread_t thread1, thread2; 
        sem_init(&mutex1, 0, 1); 
        sem_init(&mutex2, 0, 0);
        pthread_create( &thread1, NULL, &producer, NULL)
        pthread_create( &thread2, NULL, &consumer, NULL)
        pthread_join( thread1, NULL); 
        pthread_join( thread2, NULL); 
        return 0; 
     }
    
    
    void producer()
    {
      sem_wait(&mutex1); 
      :
      :
    
      sem_post(&mutex2);
    }
    
    void consumer ()
    {
        sem_wait(&mutex2); 
        :
        : 
        sem_post(&mutex1);
    }   
    
    #包括
    #包括
    #包括
    #包括
    扫描电镜;
    扫描电镜;
    int main()
    {
    pthread_t thread1,thread2;
    sem_init(&mutex1,0,1);
    sem_init(&mutex2,0,0);
    pthread_create(&thread1,NULL,&producer,NULL)
    pthread_创建(&thread2,NULL,&consumer,NULL)
    pthread_join(thread1,NULL);
    pthread_join(thread2,NULL);
    返回0;
    }
    无效生产者()
    {
    sem_wait(&mutex1);
    :
    :
    sem_post(和mutex2);
    }
    无效消费者()
    {
    sem_wait(&mutex2);
    :
    : 
    sem_post(&mutex1);
    }   
    
    互斥锁仅提供互斥(正确使用时);它们本身不提供阻止特定事件发生或直到满足特定条件的机制。这就是条件变量(和信号量,如果您想降低一点级别)

    您的代码允许使用者等待生产者生产,但不允许生产者在继续生产之前等待使用者消费。如果希望两个线程交替,则需要第二个条件变量来提供后者

    另外,在消费者方面,如果我们锁定并等待信号,生产者如何获得锁定,以便能够将信号发送给消费者

  • 会是死锁吗

  • 我的朋友建议像pthread\u cond\u wait(&cond,&mtx);实际上会解锁资源,直到它从生产者那里得到信号。这是真的吗

  • 与其问你的朋友或互联网,你是否考虑过阅读文档?以下是手册页的描述方式:

    这些函数原子地释放互斥[…]。成功返回后,互斥锁应已被锁定,且应归调用线程所有

    也就是说,调用
    pthread\u cond\u wait()
    的线程在等待时不会锁定互斥锁,但会在返回互斥锁之前重新获取互斥锁(这可能涉及线程接收信号和函数调用返回之间的不确定延迟)

    此外,请始终记住,线程可能会从等待条件变量中错误地唤醒。必须在唤醒时检查条件是否满足,如果不满足,则恢复等待

    以下是一种构建制作人的方法:

    void * producer(void * ptr)
    {
            pthread_mutex_lock(&mtx);
            while (how_many > 0)
            {
                    if (pool == 0) {
                            printf("producer: %d\n", how_many);
                            pool = how_many;
                            how_many--;
                            pthread_cond_signal(&full_cond);
                    }
                    pthread_cond_wait(&empty_cond, &mtx);
            }
            pthread_mutex_unlock(&mtx);
    
            pthread_exit(0);
    }
    
    请注意:

  • 我已经重命名了原始条件变量,并引入了一个新的条件变量。现在有
    full_-cond
    ,表示池(容量1)已满,
    empty_-cond
    ,表示池为空
  • 整个循环由互斥锁保护。这很好,因为它执行
    pthread\u cond\u wait()
    命名该互斥体;其他线程将能够在生产者等待时运行。互斥锁确保对
    多少
    变量的访问正确同步
  • 循环通过测试
    来验证其是否确实为空,从而防止虚假唤醒。如果没有,它将返回等待,而不做任何其他操作
  • 要使其正常工作,使用者需要相应的更改(留给您作为练习)

  • 您希望在解锁相关互斥锁之前,从关键部分内部发出条件信号。“我的朋友建议……这是真的吗?”根据文档,是的。我使用了sleep(1)在释放生产者端的锁后,它工作正常:-)并且我理解pthread_cond_wait()在收到信号之前不会保持锁。谢谢@John BollingerI,我知道pthread_cond_wait()在返回true之前不会保持锁:-)