一、生产者消费者模型

/*
    实现粗略的生产者消费者模型(未同步,未使用信号量)
*/

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

struct Node{
    int num;
    struct Node* next;
};
//头节点
struct Node* head = NULL;


void * producer(void*arg){
    //不断添加新节点到链表中
    while(1){
       struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
       newNode->next=head;
       newNode->num = rand() % 1000;
       head = newNode;
       printf("add node, num: %d, tid: %ld", newNode->num, pthread_self());
       usleep(100);

    }
    return NULL;
}
void * customer(void*arg){
    while(1){
        struct Node* tmp = head;
        head = head->next;
        printf("del node, num: %d, tid: %ld\n", tmp->num, pthread_self());
        free(tmp);
        usleep(100);


    }
    return NULL;
}



int main(){
    //创建5个生产者,5个消费者
    //使用链表作为容器,不考虑存储上限的问题
    pthread_t ptids[5];
    pthread_t ctids[5];
    for (int i = 0; i < 5; i++){
        pthread_create(&ptids[i], NULL, producer,NULL);
    }
    for (int i = 0; i < 5; i++){
        pthread_create(&ctids[i], NULL, customer,NULL);
    }
    for (int i = 0; i < 5; i++){
        pthread_detach(ctids[i]);
        pthread_detach(ptids[i]);
    }

    pthread_exit(NULL);
    return 0;


}

  以上代码未实现同步和信号,会产生段错误

 二、条件变量

/*
    实现生产者消费者模型(同步,使用条件变量)
    条件变量的类型pthread_cond_t,满足条件阻塞(解除阻塞)线程
    int pthread_cond_init (pthread_cond_t *restrict cond, constpthread_condattr_t *restrict attr);
    int pthread_cond_destroy(pthread_cond_t *cond) ;
    int pthread_cond_wait (pthread_cond_t *restrict cond,pthread _mutex_t *restrict mutex) ;
    功能:等待,线程会阻塞,阻塞时会暂时解锁,解除阻塞时,会重新加锁。
    int pthread_cond_timedwait (pthread_cond_t *restrict cond,
            pthread_mutex_t *restrict mutex,const struct timespec *restrictabstime) ;
    功能:等待多长时间,调用这个函数,线程会等到时间介绍
    int pthread_cond_signal(pthread_cond_t *cond) ;
    功能:唤醒一个或多个等待
    int pthread_ cond broadcast (pthread_ cond_ t *cond);
    功能:唤醒所有等待

*/

#include<stdio.h>
#include<string.h>
#include<unistd.h>
#include <pthread.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* newNode = (struct Node*)malloc(sizeof(struct Node));
        newNode->next=head;
        newNode->num = rand() % 1000;
        head = newNode;
        printf("add node, num: %d, tid: %ld\n", newNode->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* tmp = head;
        //判断是否有数据
        if(head!=NULL){
            //有数据
            head = head->next;
            printf("del node, num: %d, tid: %ld\n", tmp->num, pthread_self());
            free(tmp);
            pthread_mutex_unlock(&mutex);  
            usleep(100);
        }
        else{
            //没有数据
            pthread_cond_wait(&cond, &mutex);//阻塞时会暂时解锁,解除阻塞时,会重新加锁。
            pthread_mutex_unlock(&mutex); 
        }

    }
    return NULL;
}



int main(){
    //创建5个生产者,5个消费者
    //使用链表作为容器,不考虑存储上限的问题
    pthread_mutex_init(&mutex,NULL);
    pthread_cond_init(&cond,NULL);
    pthread_t ptids[5];
    pthread_t ctids[5];
    for (int i = 0; i < 5; i++){
        pthread_create(&ptids[i], NULL, producer,NULL);
    }
    for (int i = 0; i < 5; i++){
        pthread_create(&ctids[i], NULL, customer,NULL);
    }
    for (int i = 0; i < 5; i++){
        pthread_detach(ctids[i]);
        pthread_detach(ptids[i]);
    }
    while(1){
        sleep(10);
    }
    pthread_cond_destroy(&cond);
    pthread_mutex_destroy(&mutex);
    pthread_exit(NULL);
    return 0;
}

  以上使用条件变量和互斥锁,完成了简单的生产者消费者模型,注意wait函数阻塞时会暂时解锁。

三、信号量

  信号量可以限制同时访问线程的数量,以下为使用信号量的生产消费者模型

/*
    #include <semaphore.h>

    信号量的类型sem_t
    int sem_init (sem t *sem,int pshared, unsigned int value ) ;
        -初始化信号量
        -参数:
            sem:信号量
            pshared:0位线程间,非0位进程间
            value:信号量中的值

    int sem_destroy (sem_t *sem);
        释放信号量资源
    int sem_wait (sem_t *sem) ;
        对信号量加锁,调用一次对信号量的值-1,若值为0,则阻塞,大于0则解除阻塞
    int sem_ trywait (sem_t *sem) ;
    int sem_timedwait (sem_t *sem,const struct timespec *abs_timeout);
    int sem post ( sem_t *sem) ;
        对信号量解锁,调用一次对信号量的值+1
    int sem_getvalue (sem_ t * sem, int *sval) ;
*/
 #include <semaphore.h>
#include<stdio.h>
#include<string.h>
#include<unistd.h>
#include <pthread.h>
#include <stdlib.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* newNode = (struct Node*)malloc(sizeof(struct Node));
        newNode->next=head;
        newNode->num = rand() % 1000;
        head = newNode;
        printf("add node, num: %d, tid: %ld\n", newNode->num, pthread_self());
        //只要生产一个,就通知消费者消费

        pthread_mutex_unlock(&mutex);   
        sem_post(&csem);  
        usleep(100);
        
    }
    return NULL;
}
void * customer(void*arg){
    while(1){
        sem_wait(&csem);
        pthread_mutex_lock(&mutex);
        struct Node* tmp = head;
        head = head->next;
        printf("del node, num: %d, tid: %ld\n", tmp->num, pthread_self());
        free(tmp);
        pthread_mutex_unlock(&mutex);  
        sem_post(&psem);  
        }
return NULL;
    }
    
int main(){
    //创建5个生产者,5个消费者
    //使用链表作为容器,不考虑存储上限的问题
    pthread_mutex_init(&mutex,NULL);
    //初始化信号量
    sem_init(&psem, 0, 8);
    sem_init(&csem, 0, 0);

    pthread_t ptids[5];
    pthread_t ctids[5];
    for (int i = 0; i < 5; i++){
        pthread_create(&ptids[i], NULL, producer,NULL);
    }
    for (int i = 0; i < 5; i++){
        pthread_create(&ctids[i], NULL, customer,NULL);
    }
    for (int i = 0; i < 5; i++){
        pthread_detach(ctids[i]);
        pthread_detach(ptids[i]);
    }
    while(1){
        sleep(10);
    }

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