Linux-信号量互斥

Linux-信号量互斥

1. 消费者生产者问题

通过创建两个线程,一个代表生产者,另一个代表消费者,申请一段固定大小的内存区域表示缓冲区,向缓冲区末尾插入字符和取出字符来模拟生产消费的过程,

其中生产过程是随机生产一个小写字母放入缓冲区中,而且用nextin,nextout表示下一个要插入以及要取出的下标位置,方便下一次操作。

​ 为了保证消费者线程在插入字符时,不被生产者线程堵塞,应该通过信号量机制防止此情况发生,设置三个信号量

  • mutex::初始值为1,该信号量作用为控制一次只有一个线程可以访问缓冲区,保证消费过程和生产过程始终互斥。

  • empyt:初始值为缓冲区大小,每生产一次该信号量就减1,每消费一次该信号量就加1,当缓冲区已满时,该信号量会减小到0,这样在生产者线程开头的

    sem_wait(&empty)就会堵塞生产过程,保证缓冲区已满时不再进行生产。

  • full:初始值为0,每消费一次该信号量就减1,每生产一次该信号量就加1,当缓冲区为空时,在消费者线程开头的sem_wait(&full)就会堵塞消费过程,保证缓冲区为空时不再进行消费。

2.代码如下:

#include <unistd.h>
#include <semaphore.h>
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#define N 10
char buff[N];
int count, nextin, nextout;
sem_t mutex;
sem_t empty;
sem_t full;
int speed_producer = 1, speed_consumer = 4;

void init() {
   
    srand(time(NULL));
    sem_init(&mutex, 0, 1);
    sem_init(&empty, 0, N);
    sem_init(&full, 0, 0);
    nextin = 0;
    nextout = 0;
    count = 0; 
}

void show() {
   
    int j = count, i = nextout;
    printf("buff:");
    while (j--)
    {
   
        printf("%c", buff[i]);
        i++;
        i %= N;
        if (j != 0)
        {
   
            printf(",");
        }
    }
    printf("\n\n");
}

void *producerThread() {
   
    while (1)
    {
   
        sem_wait(&empty);
        sem_wait(&mutex);

        buff[nextin] = 'a' + rand()%26;
        printf("%c生产\n", buff[nextin]);
        nextin++;
        nextin %= N;
        count++;
        show();

        sem_post(&mutex);
        sem_post(&full); 
        sleep(speed_producer);

        
    }
}
void *consumerThread() {
   
    while (1)
    {
   
        sem_wait(&full);
        sem_wait(&mutex);

        printf("%c消费\n", buff[nextout]);
        nextout++;
        nextout %= N;
        count--;
        
        show();

        sem_post(&mutex);
        sem_post(&empty);
        sleep(speed_consumer);
       
    }
}
int main() {
   
    pthread_t producer, consumer;

    init();
    pthread_create(&producer, NULL, producerThread, NULL);
    pthread_create(&consumer, NULL, consumerThread, NULL);
    
    pthread_join(producer, NULL);
    pthread_join(consumer, NULL);

    sem_destroy(&mutex);
    sem_destroy(&empty);
    sem_destroy(&full);
    
    exit(0);
}

通过调整两个线程的延时快慢,speed_producer或者speed_consumer越大表示延时越长,速度越慢,修改这两个值即可得到不同运行效果。

运行输出解释:每次执行完生产与消费过程,程序将输出缓冲区当前**所有不为空的字符

* 当speed_consumer与speed_producer均为1,或者speed_consumer大于speed_producer时,结果均为生产一个消费一个,缓冲区始终不满。

  • 当speed_consumer为4,speed_producer均为1,每1秒生产一个字符,每4秒消费一个字符,因此缓冲区会逐渐填满。

    3. 总结

    • 掌握多线程编程方法,了解程序创建多线程的方法的原理。
    • 通过运用信号量机制进行线程互斥,对临界区原理有了进一步的认识,并且对消费者生产者问题有了进一步的理解。
全部评论

相关推荐

点赞 评论 收藏
分享
不愿透露姓名的神秘牛友
昨天 18:18
点赞 评论 收藏
分享
05-11 11:48
河南大学 Java
程序员牛肉:我是26届的双非。目前有两段实习经历,大三上去的美团,现在来字节了,做的是国际电商的营销业务。希望我的经历对你有用。 1.好好做你的CSDN,最好是直接转微信公众号。因为这本质上是一个很好的展示自己技术热情的证据。我当时也是烂大街项目(网盘+鱼皮的一个项目)+零实习去面试美团,但是当时我的CSDN阅读量超百万,微信公众号阅读量40万。面试的时候面试官就告诉我说觉得我对技术挺有激情的。可以看看我主页的美团面试面经。 因此花点时间好好做这个知识分享,最好是单拉出来搞一个板块。各大公司都极其看中知识落地的能力。 可以看看我的简历对于博客的描述。这个帖子里面有:https://www.nowcoder.com/discuss/745348200596324352?sourceSSR=users 2.实习经历有一些东西删除了,目前看来你的产出其实很少。有些内容其实很扯淡,最好不要保留。有一些点你可能觉得很牛逼,但是面试官眼里是减分的。 你还能负责数据库表的设计?这个公司得垃圾成啥样子,才能让一个实习生介入数据库表的设计,不要写这种东西。 一个公司的财务审批系统应该是很稳定的吧?为什么你去了才有RBAC权限设计?那这个公司之前是怎么处理权限分离的?这些东西看着都有点扯淡了。 还有就是使用Redis实现轻量级的消息队列?那为什么这一块不使用专业的MQ呢?为什么要使用redis,这些一定要清楚, 就目前看来,其实你的这个实习技术还不错。不要太焦虑。就是有一些内容有点虚了。可以考虑从PR中再投一点产出
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务