博客
关于我
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 order by多个字段排序
查看>>
MySQL Order By实现原理分析和Filesort优化
查看>>
mysql problems
查看>>
mysql replace first,MySQL中处理各种重复的一些方法
查看>>
MySQL replace函数替换字符串语句的用法(mysql字符串替换)
查看>>
mysql replace用法
查看>>
Mysql Row_Format 参数讲解
查看>>
mysql select, from ,join ,on ,where groupby,having ,order by limit的执行顺序和书写顺序
查看>>
MySQL Server 5.5安装记录
查看>>
mysql server has gone away
查看>>
mysql skip-grant-tables_MySQL root用户忘记密码怎么办?修改密码方法:skip-grant-tables
查看>>
mysql slave 停了_slave 停止。求解决方法
查看>>
MySQL SQL 优化指南:主键、ORDER BY、GROUP BY 和 UPDATE 优化详解
查看>>
MYSQL sql语句针对数据记录时间范围查询的效率对比
查看>>
mysql sum 没返回,如果没有找到任何值,我如何在MySQL中获得SUM函数以返回'0'?
查看>>
mysql sysbench测试安装及命令
查看>>
mysql Timestamp时间隔了8小时
查看>>
Mysql tinyint(1)与tinyint(4)的区别
查看>>
MySQL Troubleshoting:Waiting on query cache mutex
查看>>
mysql union orderby 无效
查看>>