博客
关于我
Linux多线程实践(5) --Posix信号量与互斥量解决生产者消费者问题
阅读量:792 次
发布时间: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/

你可能感兴趣的文章
Linux下查看用户列表
查看>>
LINUX下查看系统参数的常见命令
查看>>
linux下查询硬件的命令
查看>>
Linux下汇编语言学习笔记53 ---
查看>>
Linux下添加服务
查看>>
Linux下环境变量设置
查看>>
Linux下用mutt给QQ邮箱发匿名邮件
查看>>
Linux下用于查看系统当前登录用户信息 w命令
查看>>
Linux下用脚本命令打开文档、表格、PPT
查看>>
LINUX下登录脚本的执行顺序
查看>>
linux下的 lib文件的学习思考
查看>>
Linux下的64位数赋值要加入LL
查看>>
linux下的7种文件类型[ls -l]
查看>>
Linux下的PDF阅读器Foxit
查看>>
Linux下的Shell编程:基础、应用与最佳实践
查看>>
Linux下的串口系列---struct termios结构体
查看>>
Linux下的备份与恢复策略:全方位守护你的数据
查看>>
Linux下的多用户管理和认证:从入门到精通(附实例)
查看>>
Linux下的容器化技术:从入门到实践
查看>>
Linux下的文件权限与访问控制:守护你的数据宝藏
查看>>