博客
关于我
Linux多线程实践(5) --Posix信号量与互斥量解决生产者消费者问题
阅读量:805 次
发布时间:2023-02-03

本文共 3046 字,大约阅读时间需要 10 分钟。

Posix信号量

Posix信号量是一种进程间同步的机制,广泛应用于多线程程序的通信与调度。Posix信号量与System V信号量类似,主要通过信号量的名字进行操作。名字通常以"/somename"的形式标识,并且只能有一个实例,且名字长度不能超过NAME_MAX-4(即251个字符)。

Posix有名信号量的创建与管理主要通过以下函数完成:

  • sem_open:用于打开或创建有名信号量。
  • sem_close:用于关闭已打开的信号量。
  • sem_unlink:用于删除已创建的信号量。
  • sem_wait:用于等待信号量状态改变(P操作)。
  • sem_post:用于发送信号量变化通知(V操作)。

互斥锁

互斥锁是一种简单而高效的互斥机制,用于保护共享资源对原子操作的正确执行。互斥锁在多线程环境中非常有用,确保在同一时间只有一条线程能够访问共享资源。

Posix互斥锁的实现主要通过以下函数完成:

  • pthread_mutex_init:用于初始化互斥锁。
  • pthread_mutex_lock:用于上锁互斥锁。
  • pthread_mutex_trylock:用于非阻塞上锁。
  • pthread_mutex_unlock:用于解锁互斥锁。
  • pthread_mutex_destroy:用于销毁互斥锁。

Posix互斥锁可以分为快速互斥锁(默认)、递归互斥锁和检错互斥锁。快速互斥锁是最常用的版本,它在上锁时会导致等待直到互斥锁被释放。递归互斥锁允许线程在拥有互斥锁的同时递归加锁,而检错互斥锁则是非阻塞的版本,它会立即返回错误信息。

生产者与消费者问题

在Posix系统中,生产者与消费者问题通常通过信号量和互斥锁来解决。生产者负责向缓冲区中添加产品,消费者则负责从缓冲区中取走产品。为了确保缓冲区的正确使用,生产者和消费者需要对缓冲区进行互斥访问,同时确保缓冲区的充足空间和非空状态。

以下是一个典型的解决方案:

Storage类设计

class Storage {public:    Storage(unsigned int _bufferSize);    ~Storage();    void consume(int id);    void produce(int id);    void display(bool isConsumer = false);private:    unsigned int buffSize;    int *m_storage;    unsigned short int in;    unsigned short int out;    unsigned int product_number;    sem_t sem_full;    sem_t sem_empty;    pthread_mutex_t mutex;};

类实现

Storage::Storage(unsigned int _bufferSize) : buffSize(_bufferSize), in(0), out(0), product_number(0) {    m_storage = new int[buffSize];    for (unsigned int i = 0; i < buffSize; ++i)         m_storage[i] = -1;    sem_init(&sem_full, 0, 0);    sem_init(&sem_empty, 0, buffSize);    pthread_mutex_init(&mutex, NULL);}Storage::~Storage() {    delete []m_storage;    pthread_mutex_destroy(&mutex);    sem_destroy(&sem_empty);    sem_destroy(&sem_full);}

生产者与消费者代码

void Storage::produce(int id) {    printf("producer %d is waiting storage not full\n", id);    sem_wait(&sem_empty);    pthread_mutex_lock(&mutex);    m_storage[in] = product_number;    in = (in + 1) % buffSize;    pthread_mutex_unlock(&mutex);    sem_post(&sem_full);    sleep(1);}void Storage::consume(int id) {    printf("consumer %d is waiting storage not empty\n", id);    sem_wait(&sem_full);    pthread_mutex_lock(&mutex);    m_storage[out] = -1;    out = (out + 1) % buffSize;    pthread_mutex_unlock(&mutex);    sem_post(&sem_empty);    sleep(1);}

主控线程

int main() {    int nProducer = 1;    int nConsumer = 2;    cout << "please input the number of producer: ";    cin >> nProducer;    cout << "please input the number of consumer: ";    cin >> nConsumer;    cout << "please input the size of buffer: ";    int size;    cin >> size;    storage = new Storage(size);    pthread_t *thread = new pthread_t[nProducer + nConsumer];    for (int i = 0; i < nConsumer; ++i) {        pthread_create(&thread[i], NULL, consumer, new int(i));    }    for (int i = 0; i < nProducer; ++i) {        pthread_create(&thread[nConsumer + i], NULL, producer, new int(i));    }    for (int i = 0; i < nProducer + nConsumer; ++i) {        pthread_join(thread[i], NULL);    }    delete storage;    delete []thread;}

完整源代码

完整的源代码如上所示。通过合理的信号量初始化、互斥锁管理和线程创建,确保了生产者与消费者问题的高效解决。该方案能够在多线程环境中正确地管理缓冲区,避免数据竞争和死锁问题。

转载地址:http://qmzfk.baihongyu.com/

你可能感兴趣的文章
mabatis 中出现&lt; 以及&gt; 代表什么意思?
查看>>
Mac book pro打开docker出现The data couldn’t be read because it is missing
查看>>
MAC M1大数据0-1成神篇-25 hadoop高可用搭建
查看>>
mac mysql 进程_Mac平台下启动MySQL到完全终止MySQL----终端八步走
查看>>
Mac OS 12.0.1 如何安装柯美287打印机驱动,刷卡打印
查看>>
MangoDB4.0版本的安装与配置
查看>>
Manjaro 24.1 “Xahea” 发布!具有 KDE Plasma 6.1.5、GNOME 46 和最新的内核增强功能
查看>>
mapping文件目录生成修改
查看>>
MapReduce程序依赖的jar包
查看>>
mariadb multi-source replication(mariadb多主复制)
查看>>
MariaDB的简单使用
查看>>
MaterialForm对tab页进行隐藏
查看>>
Member var and Static var.
查看>>
memcached高速缓存学习笔记001---memcached介绍和安装以及基本使用
查看>>
memcached高速缓存学习笔记003---利用JAVA程序操作memcached crud操作
查看>>
Memcached:Node.js 高性能缓存解决方案
查看>>
memcache、redis原理对比
查看>>
memset初始化高维数组为-1/0
查看>>
Metasploit CGI网关接口渗透测试实战
查看>>
Metasploit Web服务器渗透测试实战
查看>>