Linux C/C++生产者消费者模型-条件变量-信号量

  • Post author:
  • Post category:linux





一、生产者消费者模型



1.生产者消费者模型是什么

生产者消费者模式 是Controlnet网络中特有的一种传输数据的模式。用于两个CPU之间传输数据,即使是不同类型同一厂家的CPU也可以通过设置来使用。



2.生产者消费者简单代码案例(互斥锁解决)

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

//创建一个互斥量
pthread_mutex_t mutex;

struct Node
{
    int num;
    struct Node* next;
};

//头节点
struct Node* head=NULL;




void* producer(void* arg)
{
    //不断地创建新的节点,添加到链表中
    while(1)
    {
        pthread_mutex_lock(&mutex);
        struct Node* s = (struct Node*)malloc(sizeof(struct Node));
        s->next=head;
        head=s;
        s->num=rand()%1000;
        printf("add node,num:%d,tid:%ld\n",s->num,pthread_self());
        pthread_mutex_unlock(&mutex);
        usleep(100);
    }

    return NULL;
}

void* customer(void* arg)
{
    while(1)
    {
        pthread_mutex_lock(&mutex);
        struct Node* p=head;
        if(head!=NULL)
        {
        head=head->next;
        printf("del node,num :%d,tid:%ld\n",p->num,pthread_self());
        free(p);
        pthread_mutex_unlock(&mutex);
        usleep(100);
        continue;
        }
        pthread_mutex_unlock(&mutex);
        
    }

    return NULL;
}


int main()
{
    pthread_mutex_init(&mutex,NULL);

    //创建5个生产者线程
    //创建5个消费者线程
    pthread_t ptid[5];
    pthread_t ctid[5];

    for(int i=0;i<5;i++)
    {
        pthread_create(&ptid[i],NULL,producer,NULL);
        pthread_create(&ctid[i],NULL,customer,NULL);
    }

    for(int i=0;i<5;i++)
    {
        pthread_detach(ptid[i]);
        pthread_detach(ctid[i]);
    }

    while(1)
    {
        sleep(10);
    }

    pthread_mutex_destroy(&mutex);
    pthread_exit(NULL);
    
    
    
}



二、条件变量解决



1.条件变量是什么

条件变量是利用线程间共享的全局变量进行同步的一种机制,主要包括两个动作:一个线程等待”条件变量的条件成立”而挂起;另一个线程使”条件成立”(给出条件成立信号)。为了防止竞争,条件变量的使用总是和一个互斥锁结合在一起。



2.条件变量常用函数

在这里插入图片描述



3.条件变量解决问题

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

//创建一个互斥量
pthread_mutex_t mutex;
//创建条件变量
pthread_cond_t cond;

struct Node
{
    int num;
    struct Node* next;
};

//头节点
struct Node* head=NULL;




void* producer(void* arg)
{
    //不断地创建新的节点,添加到链表中
    while(1)
    {
        pthread_mutex_lock(&mutex);
        struct Node* s = (struct Node*)malloc(sizeof(struct Node));
        s->next=head;
        head=s;
        s->num=rand()%1000;
        printf("add node,num:%d,tid:%ld\n",s->num,pthread_self());

        //只要生产了一个,就通知消费者消费
        pthread_cond_signal(&cond);

        pthread_mutex_unlock(&mutex);
        usleep(100);
    }

    return NULL;
}

void* customer(void* arg)
{
    while(1)
    {
        pthread_mutex_lock(&mutex);
        struct Node* p=head;
        if(head!=NULL)
        {
        head=head->next;
        printf("del node,num :%d,tid:%ld\n",p->num,pthread_self());
        free(p);
        pthread_mutex_unlock(&mutex);
        usleep(100);
        }else{
            //没有数据,需要等待
            //当这个函数调用阻塞的时候,会对互斥锁进行解锁,当不阻塞时,继续加锁
            pthread_cond_wait(&cond,&mutex);
            pthread_mutex_unlock(&mutex);
        }
        
        
    }

    return NULL;
}


int main()
{
    pthread_mutex_init(&mutex,NULL);
    pthread_cond_init(&cond,NULL);

    //创建5个生产者线程
    //创建5个消费者线程
    pthread_t ptid[5];
    pthread_t ctid[5];

    for(int i=0;i<5;i++)
    {
        pthread_create(&ptid[i],NULL,producer,NULL);
        pthread_create(&ctid[i],NULL,customer,NULL);
    }

    for(int i=0;i<5;i++)
    {
        pthread_detach(ptid[i]);
        pthread_detach(ctid[i]);
    }

    while(1)
    {
        sleep(10);
    }


    pthread_mutex_destroy(&mutex);
    pthread_cond_destroy(&cond);
    pthread_exit(NULL);
      
    return 0;
}



三、信号量解决



1.信号量是什么

信号量(Semaphore),有时被称为信号灯,是在多线程环境下使用的一种设施,是可以用来保证两个或多个关键代码段不被并发调用。在进入一个关键代码段之前,线程必须获取一个信号量;一旦该关键代码段完成了,那么该线程必须释放信号量。其它想进入该关键代码段的线程必须等待直到第一个线程释放信号量。为了完成这个过程,需要创建一个信号量VI,然后将Acquire Semaphore VI以及Release Semaphore VI分别放置在每个关键代码段的首末端。确认这些信号量VI引用的是初始创建的信号量。



2.信号量函数

在这里插入图片描述



3.信号量解决

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

//创建一个互斥量
pthread_mutex_t mutex;
//创建两个信号量
sem_t psem;
sem_t csem;


struct Node
{
    int num;
    struct Node* next;
};

//头节点
struct Node* head=NULL;




void* producer(void* arg)
{
    //不断地创建新的节点,添加到链表中
    while(1)
    {
        sem_wait(&psem);
        pthread_mutex_lock(&mutex);
        struct Node* s = (struct Node*)malloc(sizeof(struct Node));
        s->next=head;
        head=s;
        s->num=rand()%1000;
        printf("add node,num:%d,tid:%ld\n",s->num,pthread_self());
        pthread_mutex_unlock(&mutex);
        sem_post(&csem);
    }

    return NULL;
}

void* customer(void* arg)
{
    while(1)
    {
        sem_wait(&csem);
        pthread_mutex_lock(&mutex);
        struct Node* p=head;
        head=head->next;
        printf("del node,num :%d,tid:%ld\n",p->num,pthread_self());
        free(p);
        pthread_mutex_unlock(&mutex);
        sem_post(&psem);
          
    }

    return NULL;
}


int main()
{
    pthread_mutex_init(&mutex,NULL);
    sem_init(&psem,0,8);
    sem_init(&csem,0,0);

    //创建5个生产者线程
    //创建5个消费者线程
    pthread_t ptid[5];
    pthread_t ctid[5];

    for(int i=0;i<5;i++)
    {
        pthread_create(&ptid[i],NULL,producer,NULL);
        pthread_create(&ctid[i],NULL,customer,NULL);
    }

    for(int i=0;i<5;i++)
    {
        pthread_detach(ptid[i]);
        pthread_detach(ctid[i]);
    }

    while(1)
    {
        sleep(10);
    }


    pthread_mutex_destroy(&mutex);
    pthread_exit(NULL);
      
    return 0;
}



总结

今天主要给大家介绍了生产者消费模型中的一些问题,以及一些具体的解决方案,例如使用条件变量和信号量。



版权声明:本文为Abieai原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。