5.线程与并发同步-条件变量pthread_cond_t 实现生产者消费者

本文介绍了条件变量pthread_cond_t在多线程同步中的作用,它不作为锁但可以导致线程阻塞。结合互斥锁使用,用于线程间会合。通过示例展示了如何使用条件变量实现生产者消费者模型,详细解析了pthread_cond_wait、pthread_cond_signal和pthread_cond_broadcast函数的工作原理,并给出了不同数量生产者和消费者运行的示例输出。

条件变量本身不是锁!但它也可以造成线程阻塞。通常与互斥锁配合使用。给多线程提供一个会合的场所。

使用STL标准库queue队列
入队—模仿生产
出队—模仿消费

pthread_cond_wait函数
阻塞等待一个条件变量
int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);
函数作用:
1.阻塞等待条件变量cond(参1)满足
2.释放已掌握的互斥锁(解锁互斥量)相当于pthread_mutex_unlock(&mutex);
1.2.两步为一个原子操作。
3.当被唤醒,pthread_cond_wait函数返回时,解除阻塞并重新申请获取互斥锁pthread_mutex_lock(&mutex);

pthread_cond_signal函数
唤醒至少一个阻塞在条件变量上的线程
int pthread_cond_signal(pthread_cond_t *cond);

pthread_cond_broadcast函数
唤醒全部阻塞在条件变量上的线程
int pthread_cond_broadcast(pthread_cond_t *cond);
一个生产者,一个消费者

#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <stdio.h>
#include <queue>

using namespace std;

pthread_cond_t has_product = PTHREAD_COND_INITIALIZER;
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;

queue<int>my_Queue;  //产品队列

void *consumer(void *p)
{
    for (;;) {
        pthread_mutex_lock(&lock);
        while (my_Queue.empty()) {          
            pthread_cond_wait(&has_product, &lock);
        }
		//模拟消费掉一个产品
        int num=my_Queue.front(); //获取队头元素
		my_Queue.pop();//出队
        pthread_mutex_unlock(&lock);
        
        printf("-Consume ---%d, now total = %lu\n", num,my_Queue.size());
        
        sleep(rand() % 2+1);
    }
}
void *producer(void *p)
{
    while (1) {
	
	    int num= rand() % 1000 + 1;        //模拟生产一个产品
	    
        pthread_mutex_lock(&lock);
        my_Queue.push (num);	//产品入队
        pthread_mutex_unlock(&lock);
        
	   printf("-Produce ---%d, now total = %lu\n", num,my_Queue.size());
        pthread_cond_signal(&has_product);  //将等待在该条件变量上的一个线程唤醒
        
        sleep(rand() % 2);
    }
}
int main(int argc, char *argv[])
{
    pthread_t pid, cid;
    srand(time(NULL));

    pthread_create(&pid, NULL, producer, NULL);
    pthread_create(&cid, NULL, consumer, NULL);

    pthread_join(pid, NULL);
    pthread_join(cid, NULL);
    return 0;
}	

编译输出
g++ s.cpp -pthread
./a.out

-Produce —77, now total = 1
-Consume —77, now total = 0
-Produce —140, now total = 1
-Consume —140, now total = 0
-Produce —231, now total = 1
-Produce —343, now total = 2
-Consume —231, now total = 1
-Produce —426, now total = 2
-Produce —691, now total = 3
-Consume —343, now total = 2
-Produce —414, now total = 3
-Consume —426, now total = 2
-Produce —640, now total = 3
-Produce —357, now total = 4
-Consume —691, now total = 3
-Produce —905, now total = 4
^C

一个生产者,3个消费者

clude <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <stdio.h>
#include <queue>

using namespace std;

pthread_cond_t has_product = PTHREAD_COND_INITIALIZER;
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;

queue<int>my_Queue;  //产品队列

void *consumer(void *p)
{
    for (;;) {
        pthread_mutex_lock(&lock);
        while (my_Queue.empty()) {          
            pthread_cond_wait(&has_product, &lock);
        }
		//模拟消费掉一个产品
        int num=my_Queue.front(); //获取队头元素
		my_Queue.pop();//出队
        pthread_mutex_unlock(&lock);
        
        printf("-Consume ---%d, thread id = %lu, now total num = %lu\n", num,pthread_self(),my_Queue.size());//打印消费的产品,消费者线程id,剩余产品数量
        
        sleep(rand() % 2+2);
    }
}
void *producer(void *p)
{
    while (1) {
	
	    int num= rand() % 1000 + 1;        //模拟生产一个产品
	    
        pthread_mutex_lock(&lock);
        my_Queue.push (num);	//产品入队
        pthread_mutex_unlock(&lock);
        
	    printf("-Produce ---%d, now total num = %lu\n", num,my_Queue.size());
        pthread_cond_broadcast(&has_product);  //将等待在该条件变量上的所有线程唤醒
        
        sleep(rand() % 2);
    }
}
int main(int argc, char *argv[])
{
    int i;
    pthread_t pid, cid[3];
    srand(time(NULL));

    pthread_create(&pid, NULL, producer, NULL);
	
	for(i=0;i<3;i++)
        pthread_create(&cid[i], NULL, consumer, NULL);
	

    pthread_join(pid, NULL);
	
	for(i=0;i<3;i++)
        pthread_join(cid[i], NULL);
		
    return 0;
}

g++ cond2.c -pthread
./a.out

-Produce —305, now total num = 1
-Consume —305, thread id = 140698680510208, now total num = 0
-Produce —219, now total num = 1
-Consume —219, thread id = 140698688902912, now total num = 0
-Produce —297, now total num = 1
-Consume —297, thread id = 140698697295616, now total num = 0
-Produce —544, now total num = 1
-Produce —307, now total num = 2
-Consume —544, thread id = 140698680510208, now total num = 1
-Produce —163, now total num = 2
-Produce —997, now total num = 3
-Produce —829, now total num = 4
-Produce —829, now total num = 5
-Consume —307, thread id = 140698688902912, now total num = 4
-Consume —163, thread id = 140698697295616, now total num = 3
-Produce —850, now total num = 4
-Consume —997, thread id = 140698680510208, now total num = 3
-Produce —95, now total num = 4
-Produce —802, now total num = 5
-Consume —829, thread id = 140698688902912, now total num = 4
-Consume —829, thread id = 140698697295616, now total num = 3
-Produce —110, now total num = 4
-Produce —452, now total num = 5
-Produce —827, now total num = 6
^C

实验二 线程同步 一、实验目的 1.加深对并发执行、共享资源访问等概念的理解; 2.初步掌握多线程同步技术,如互斥锁、信号量、条件变量等。 二、实验题 生产者-消费者模型是多线程编程中一个经典的同步问题。在这个模型中,生产者线程负责生产产品并将其放入缓冲区,消费者线程负责从缓冲区中取出产品并消费。为了确保线程安全,需要使用互斥锁和条件变量同步生产者消费者的操作。 用C/C++模拟实现一个生产者消费者模型。 要求:设计一个循环缓冲区用于存放生产者生产的产品(用一个整数表示产品,缓冲区用数组表示),设计两个线程,一个用于生产产品并放入缓冲区,一个从缓冲区中取出产品消费。注意对缓冲区互斥访问,使用C或C++中有关线程同步的函数实现。 提示: 可以使用互斥锁访问缓冲区。 1.先创建一个互斥锁的对象。互斥锁的类型是pthread_mutex_t,所以定义一个变量 pthread_mutex_t mutex; 就创建了一个互斥锁。 如果想使用这个互斥锁,我们还需要对这个互斥锁进行初始化,使用函数 pthread_mutex_init() 对互斥锁进行初始化操作。 方法为:pthread_mutex_init(&mutex, NULL); 2.使用互斥锁进行互斥操作。 在进行互斥操作的时候,应该先"拿到锁"再执行需要互斥的操作,否则可能会导致多个线程都需要访问的数据结果不一致。例如在一个线程在试图修改一个变量的时候,另一个线程也试图去修改这个变量,那就很可能让后修改的这个线程把前面线程所做的修改覆盖了。 (1)阻塞调用 pthread_mutex_lock(&mutex); 这个操作是阻塞调用。如果这个锁此时正在被其它线程占用,那么 pthread_mutex_lock() 调用会进入到这个锁的排队队列中,并会进入阻塞状态, 直到拿到锁之后才会返回。 (2)释放互斥锁。用完了互斥锁,一定要记得释放,不然下一个想要获得这个锁的线程,就会一直等待。使用 pthread_mutex_unlock() 即可释放互斥锁。 pthread_mutex_unlock(&mutex); 用条件变量判断缓冲区空或者满。 pthread库中用于线程同步的一种机制。在多线程程序中,条件变量通常互斥锁(pthread_mutex_t)一起使用,以防止并发问题,如竞态条件和死锁。 (1)条件变量(pthread_cond_t)操作函数pthread_cond_init() 初始化一个条件变量。 int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr) 如: pthread_cond_t not_full; pthread_cond_init(&not_full, NULL); (2) pthread_cond_wait 在等待条件变量时,阻塞线程并释放互斥锁。当被pthread_cond_signal或pthread_cond_broadcast唤醒时,线程重新获得锁,并继续执行。 int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex); (3)pthread_cond_signal 唤醒至少一个等待给定条件变量线程。 int pthread_cond_signal(pthread_cond_t *cond); (4) pthread_cond_destroy 销毁条件变量。 int pthread_cond_destroy(pthread_cond_t *cond); 对实验进行总结200字
最新发布
10-29
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值