Linux(十三)线程(信号量与生产者与消费者模型)

在前面的进程控制里面我们说到了System V版本的信号量,主要用于进程控制。同样,线程控制里面也有相应的信号量,它用于线程间同步,就是我们下面要讲的Posix信号量
说到信号量,我们都明白,信号量就相当于一个计数器,它的目的是为了保护临界资源,通过信号量的P,V操作,就可以对临界资源的数目进行修改

POSIX信号量
初始化信号量

#include<semaphore.h>
int sem_init(seq_t *sem,int pshared,unsifned int value);

参数:
    pshared:0表示线程间共享,非零表示进程间共享
    value:信号量的初始值

销毁信号量

int sem_destroy(sem_t *sem);

等待信号量

功能:等待信号量, 将信号量的值减一
int sem_wait(sem_t *sem);

发布信号量

功能:发布信号量,表示资源使用完毕,可以归还资源了,将信号量值加一
int sem_post(sem_t *sem);

接下来我们通过一个具体的例子了解信号量的作用

消费者与生产者模型
消费者和生产者我们都知道
生产者生产后放到仓库,消费者拿去消费
那么问题来了!!!
当生产者生产的慢,消费者比较多的时候,就会出现,消费者一直申请锁释放锁,线程死锁问题,
如果是消费者慢,生产者快,那么在一个环状结构中,生产者生产的新的数据就会把之前的数据覆盖掉产生严重的后果

下面先看一个没有信号量的

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


#define CONSUMERS_COUNT 2
#define PRODUCERS_COUNT 2

struct msg{
    struct msg *next;
    int num;
};
struct msg *head = NULL;
pthread_cond_t cond;
pthread_mutex_t mutex;
pthread_t threads[CONSUMERS_COUNT + PRODUCERS_COUNT];
void *consumer(void *p)
{
    int num = *(int *)p;
    free(p);
    struct msg *mp;
    for(;;){
        pthread_mutex_lock(&mutex);
        while(head == NULL)
        {
            printf("%d begin wait a condition...\n",num);
            pthread_cond_wait(&cond,&mutex);
        }
        printf("%d end wait a condition...\n",num);
        printf("%d begin consume product...\n",num);
        mp = head;
        head = mp->next;
        pthread_mutex_unlock(&mutex);
        printf("consume %d\n",mp->num);
        free(mp);
        printf("%d end consumer product...\n",num);
        sleep(rand()%5);
    }
}
void *producer(void *p)
{
    struct msg *mp;
    int num = *(int *)p;
    free(p);
    for(;;)
    {
        printf("%d begin product product...\n",num);
        mp = (struct msg*)malloc(sizeof(struct msg));
        mp ->num = rand()%1000 + 1;
        printf("produce %d\n",mp->num);
        pthread_mutex_lock(&mutex);
        mp->next = head;
        head = mp;
        printf("%d end produce product...\n",num);

        pthread_cond_signal(&cond);
        pthread_mutex_unlock(&mutex);
        sleep(rand()%5);
    }
}
int main(void)
{
    srand(time(NULL));

    pthread_cond_init(&cond,NULL);
    pthread_mutex_init(&mutex,NULL);

    int i;
    for(i = 0;i < CONSUMERS_COUNT;i++)
    {
        int *p = (int *)malloc(sizeof(int));
        *p = i;
        pthread_create(&threads[i],NULL,consumer,(void*)p);
    }

    for(i = 0;i<PRODUCERS_COUNT;i++)
    {
        int *p = (int *)malloc(sizeof(int));
        *p = i;
        pthread_create(&threads[CONSUMERS_COUNT+1],NULL,producer,(void*)p);
    }
    for(i = 0;i < CONSUMERS_COUNT+PRODUCERS_COUNT;i++)
    {
        pthread_join(threads[i],NULL);
    }
    pthread_mutex_destroy(&mutex);
    pthread_cond_destroy(&cond);
}

这里写图片描述
我们可以看到生产者与消费者之间会出现问题

所以我们在环状的生产者与消费者之间加上信号量来看看

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/types.h>
#include <semaphore.h>
#include <errno.h>
#include <string.h>

//#define ERR_EXIT(m);
//do
//{
//    perror(m);
//    exit(EXIT_FALLURE);
//}while(0)

#define CONSUMERS_COUNT 1
#define PRODUCERS_COUNT 1
#define BUFFSIZE 10

int g_buffer[BUFFSIZE];
unsigned short in = 0;
unsigned short out = 0;
unsigned short produce_id = 0;
unsigned short consume_id = 0;

sem_t g_sem_full;
sem_t g_sem_empty;
pthread_mutex_t g_mutex;
pthread_t g_threads[CONSUMERS_COUNT + PRODUCERS_COUNT];
void *consumer(void *p)
{
    int i;
    int num = *(int *)p;
    free(p);
    while(1){
        printf("%d wait buffer not empty\n",num);
        sem_wait(&g_sem_empty);
        pthread_mutex_lock(&g_mutex);
        for(i = 0;i < BUFFSIZE;i++)
        {
            printf("%2d",i);
            if(g_buffer[i] == -1)
            {
                printf("%s","null");
            }
            else
            {
                printf("%d",g_buffer[i]);
            }
            if(i == out)
            {
                printf("\t < --consume");
            }
            printf("\n");
        }
        consume_id = g_buffer[out];
        printf("%d begin consume product %d\n",num,consume_id);
        g_buffer[out] = -1;
        out = (out + 1) % BUFFSIZE;
        printf("%d end consume product %d\n",num,consume_id);
        pthread_mutex_unlock(&g_mutex);
        sem_post(&g_sem_full);
        sleep(1);
    }
    return NULL;
}
void *producer(void *p)
{
    int i;
    int num = *(int *)p;
    free(p);
    while(1)
    {
        printf("%d wait buffer not full\n",num);
        sem_wait(&g_sem_full);
        pthread_mutex_lock(&g_mutex);
        for(i = 0;i < BUFFSIZE;i++)
        {
            printf("%2d",i);
            if(g_buffer[i] == -1)
            {
                printf("%s","null");
            }
            else
            {
                printf("%d",g_buffer[i]);
            }
            if(i == in)
            {
                printf("\t < --produce");
            }
            printf("\n");
        }
        printf("%d begin produce product %d\n",num,produce_id);
        g_buffer[in] = produce_id;
        in = (in +1) % BUFFSIZE;
        printf("%d end produce product %d",num,produce_id);
        pthread_mutex_unlock(&g_mutex);
        sem_post(&g_sem_empty);
        sleep(5);

    }
    return NULL;
}
int main(void)
{
    int i;
    for(i = 0; i < BUFFSIZE;i++)
    {
        g_buffer[i] = -1;
    }
    sem_init(&g_sem_full,0,BUFFSIZE);
    sem_init(&g_sem_empty,0,BUFFSIZE);
    pthread_mutex_init(&g_mutex,NULL);
    //srand(time(NULL));

    //pthread_cond_init(&cond,NULL);
    //pthread_mutex_init(&mutex,NULL);

    //int i;
    for(i = 0;i < CONSUMERS_COUNT;i++)
    {
        int *p = (int *)malloc(sizeof(int));
        *p = i;
        pthread_create(&g_threads[i],NULL,consumer,(void*)p);
    }

    for(i = 0;i<PRODUCERS_COUNT;i++)
    {
        int *p = (int *)malloc(sizeof(int));
        *p = i;
        pthread_create(&g_threads[CONSUMERS_COUNT+1],NULL,producer,(void*)p);
    }
    for(i = 0;i < CONSUMERS_COUNT+PRODUCERS_COUNT;i++)
    {
        pthread_join(g_threads[i],NULL);
    }
    sem_destroy(&g_sem_full);
    sem_destroy(&g_sem_empty);
    pthread_mutex_destroy(&g_mutex);
    return 0;
}

这里写图片描述
由此我们可以看出,生产者生产出来的东西不会因为,消费者快而产生死锁问题,也不会因为生产者快而产生数据覆盖问题

信号量较好的解决了出现的问题

猜你喜欢

转载自blog.csdn.net/mignatian/article/details/80353510