博客
关于我
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/

你可能感兴趣的文章
MySQL中的DB、DBMS、SQL
查看>>
MySQL中的DECIMAL类型:MYSQL_TYPE_DECIMAL与MYSQL_TYPE_NEWDECIMAL详解
查看>>
MySQL中的GROUP_CONCAT()函数详解与实战应用
查看>>
MySQL中的IO问题分析与优化
查看>>
MySQL中的ON DUPLICATE KEY UPDATE详解与应用
查看>>
mysql中的rbs,SharePoint RBS:即使启用了RBS,内容数据库也在不断增长
查看>>
mysql中的undo log、redo log 、binlog大致概要
查看>>
Mysql中的using
查看>>
MySQL中的关键字深入比较:UNION vs UNION ALL
查看>>
mysql中的四大运算符种类汇总20多项,用了三天三夜来整理的,还不赶快收藏
查看>>
mysql中的字段如何选择合适的数据类型呢?
查看>>
MySQL中的字符集陷阱:为何避免使用UTF-8
查看>>
mysql中的数据导入与导出
查看>>
MySQL中的时间函数
查看>>
mysql中的约束
查看>>
MySQL中的表是什么?
查看>>
mysql中穿件函数时候delimiter的用法
查看>>
Mysql中索引的分类、增删改查与存储引擎对应关系
查看>>
Mysql中索引的最左前缀原则图文剖析(全)
查看>>
MySql中给视图添加注释怎么添加_默认不支持_可以这样取巧---MySql工作笔记002
查看>>