• 【C/C++多线程编程之七】pthread信号量


    多线程编程之信号量


         Pthread是 POSIX threads 的简称。是POSIX的线程标准
             相互排斥量用来处理一个共享资源的同步訪问问题,当有多个共享资源时,就须要用到信号量机制。

             信号量机制用于保证两个或多个共享资源被线程协调地同步使用。信号量的值相应当前可用资源的数量。

             1.信号量samaphore):

            信号量机制通过信号量的值控制可用资源的数量。线程訪问共享资源前,须要申请获取一个信号量,假设信号量为0。说明当前无可用的资源,线程无法获取信号量,则该线程会等待其它资源释放信号量(信号量加1)。假设信号量不为0。说明当前有可用的资源,此时线程占用一个资源,相应信号量减1。

            举例:
            停车场有5个停车位,汽车可使用停车位。在这里5个停车位是共享的资源。汽车是线程。開始信号量为5,表明此时有5个停车位可用。一辆汽车进入停车场前。先查询信号量的值,不为0表明有可用停车位,汽车进入停车场并使用一个停车位。信号量减1。表明占用一个停车位,可用数降低。
           
               2.信号量基本函数
             #include <semaphore.h>
    初始化信号量:
            int sem_init(sem_t *sem, int pshared, unsigned int val);
            该函数第一个參数为信号量指针,第二个參数为信号量类型(一般设置为0)。第三个为信号量初始值。第二个參数pshared为0时,该进程内全部线程可用。不为0时不同进程间可用。
    信号量减1:
            int sem_wait(sem_t *sem);
            该函数申请一个信号量。当前无可用信号量则等待,有可用信号量时占用一个信号量。对信号量的值减1。


    信号量加1:
            int sem_post(sem_t *sem);

            该函数释放一个信号量。信号量的值加1。


    销毁信号量:
            int sem_destory(sem_t *sem);

            该函数销毁信号量。       

            3.牛刀小试
            採用信号量机制,解决苹果橙子问题:一个能放N(这里N设为3)个水果的盘子。爸爸仅仅往盘子里放苹果。妈妈仅仅放橙子。女儿仅仅吃盘子里的橙子,儿子仅仅吃苹果。
            採用三个信号量:
            1.sem_t empty:信号量empty控制盘子可放水果数,初始为3,由于開始盘子为空可放水果数为3。
            2.sem_t  apple ;信号量apple控制儿子可吃的苹果数。初始为0。由于開始盘子里没苹果。
            3.sem_t orange;信号量orange控制女儿可吃的橙子是。初始为0,由于開始盘子里没橙子。

    注:相互排斥量work_mutex仅仅为printf输出时可以保持一致,可忽略。
     
    #include 
    #include 
    #include 
    #include 
    #pragma comment(lib, "pthreadVC2.lib")     //必须加上这句
    sem_t empty;  //控制盘子里可放的水果数
    sem_t apple;  //控制苹果数
    sem_t orange; //控制橙子数
    pthread_mutex_t work_mutex;                    //声明相互排斥量work_mutex
    void *procf(void *arg) //father线程
              { 
                 while(1){
                     sem_wait(&empty);     //占用一个盘子空间,可放水果数减1
                     pthread_mutex_lock(&work_mutex);     //加锁
                     printf("爸爸放入一个苹果!
    ");
                     sem_post(&apple);     //释放一个apple信号了。可吃苹果数加1
                     pthread_mutex_unlock(&work_mutex);   //解锁
                     Sleep(3000);
                 }
    
               }
    void *procm(void *arg)  //mother线程
              { 
                while(1){
                    sem_wait(&empty);
                    pthread_mutex_lock(&work_mutex);     //加锁
                    printf("妈妈放入一个橙子!
    ");
                    sem_post(&orange);
                    pthread_mutex_unlock(&work_mutex);   //解锁
                    Sleep(4000);
                }
               }
    void *procs(void *arg)  //son线程
              { 
                while(1){
                    sem_wait(&apple);       //占用一个苹果信号量。可吃苹果数减1 
                    pthread_mutex_lock(&work_mutex);     //加锁
                    printf("儿子吃了一个苹果!
    ");
                    sem_post(&empty);       //吃了一个苹果,释放一个盘子空间,可放水果数加1
                    pthread_mutex_unlock(&work_mutex);   //解锁
                    Sleep(1000);
                }
               }
    void *procd(void *arg)  //daughter线程
              { 
                while(1){
                    sem_wait(&orange);
                    pthread_mutex_lock(&work_mutex);     //加锁
                    printf("女儿吃了一个橙子!
    ");
                    sem_post(&empty);
                    pthread_mutex_unlock(&work_mutex);   //解锁
                    Sleep(2000);
                }
    
               }
    
    void main()
    { 
        pthread_t father;  //定义线程
        pthread_t mother;
        pthread_t son;
        pthread_t daughter;
    
        sem_init(&empty, 0, 3);  //信号量初始化
        sem_init(&apple, 0, 0);
        sem_init(&orange, 0, 0);
    	pthread_mutex_init(&work_mutex, NULL);   //初始化相互排斥量
    
        pthread_create(&father,NULL,procf,NULL);  //创建线程
        pthread_create(&mother,NULL,procm,NULL);
        pthread_create(&daughter,NULL,procd,NULL);
        pthread_create(&son,NULL,procs,NULL);
    
        Sleep(1000000000);
    }
    


  • 相关阅读:
    openOPC与监控页面二
    Node教程——Gulp前端构建工具-教程
    回到顶部插件
    《软件测试52讲》——测试基础知识篇
    计算贝塞尔曲线上点坐标
    少年,不要滥用箭头函数啊
    JS属性defer
    leetcode-572-另一个树的子树
    leetcode-9.-回文数
    leetcode-300-最长上升子序列
  • 原文地址:https://www.cnblogs.com/ldxsuanfa/p/10090552.html
Copyright © 2020-2023  润新知