• linux应用编程之进程间同步


    一、描述

          在操作系统中,异步并发执行环境下的一组进程,因为相互制约关系,进而互相发送消息、互相合作、互相等待,使得各进程按一定的顺序和速度执行,称为进程间的同步。具有同步关系的一组并发进程,称为合作进程,合作进程间互相发送的信号,称为消息或事件。

          这种需要进程间同步的情况,是可以想见的,例如几个进程访问“临界资源”。而为了解决进程间的同步问题,引入信号量的概念。

    二、异步执行

      所谓异步执行命令,就是说一个线程用于接收解析命令,另外一个线程用于实际执行命令。实际工程中,经常会遇到有许多种命令要在一个线程中得到解析并执行,有些命令耗时短,可以在这个线程中完成;但是,有些命令耗时长,如果也放在这个线程中,则影响该线程接收(其他命令)。所以,此时可以考虑用异步执行的方案,将耗时短的命令,就放在接收解析线程中;而将耗时长的命令,则用异步执行的方案,将接收与实际执行分离,以避免接收线程受到严重阻塞。

    example:

        本例程中,用主线程创建了两个子线程pthread1和pthread2,其中线程pthread1用于产生命令(模仿接受解析过程),而线程pthread2用于实际执行命令。

    代码如下:

      1 #include<stdio.h>
      2 #include<stdlib.h>
      3 #include<pthread.h>
      4 #include <semaphore.h>
      5 
      6 /* 将信号量定义为全局变量,方便多个线程共享 */
      7 sem_t sem;
      8 
      9 /* 线程1和线程2的公用命令 */ 
     10 int gCmd = 0;
     11 
     12 /* 同步线程1和线程2的全局变量 */
     13 static int gIsExecFlag = 0;
     14 
     15 /* 定义线程pthread1 */
     16 static void * pthread1(void *arg)       
     17 {    
     18     /* 线程pthread1开始运行 */
     19     printf("pthread1 start!
    ");
     20     
     21     while(1)
     22     {
     23         /* 等待没有命令正在执行 */
     24         while(gIsExecFlag);
     25         
     26         /* 更新命令 */
     27         gCmd++;
     28         if(gCmd == 10)
     29         {
     30             /* 释放信号量 */
     31             sem_post(&sem);
     32         
     33             /* 发送命令结束 */
     34             return NULL;
     35         }
     36     
     37         /* 释放信号量 */
     38         sem_post(&sem);
     39         
     40         /* 等待线程2执行命令 */
     41         sleep(1);
     42     }
     43 }
     44 
     45 /* 定义线程pthread2 */
     46 static void * pthread2(void *arg)       
     47 {
     48     int tmp;
     49     
     50     /* 线程pthread2开始运行 */
     51     printf("pthread2 start!
    ");
     52     
     53     while(1)
     54     {
     55         if (sem_wait(&sem) != 0)
     56         {
     57             printf("Error!
    ");
     58         }
     59         
     60         /* 正在执行的标志置1 */
     61         gIsExecFlag = 1;
     62         
     63         /* 线程2接受来自线程1的命令,并打印 */
     64         tmp = gCmd;
     65         printf("now execute the cmd,and the code of cmd is %d.
    ", tmp);
     66         
     67         /* 执行命令需要时间:3s,模仿实际命令执行 */
     68         sleep(3);
     69         
     70         /* 正在执行的标志清0 */
     71         gIsExecFlag = 0;
     72         
     73         if(gCmd == 10){
     74             /* 命令执行结束 */
     75             return NULL;
     76         }
     77     }
     78 }
     79 
     80 /* main函数 */
     81 int main(int agrc,char* argv[])
     82 {
     83     pthread_t tidp1,tidp2;            
     84     
     85     /* 初始化信号量sem,注意初始值为0 */
     86     sem_init(&sem, 0, 0);
     87      
     88     /* 创建线程pthread1 */
     89     if ((pthread_create(&tidp1, NULL, pthread1, NULL)) == -1)
     90     {
     91         printf("create error!
    ");
     92         return 1;
     93     }
     94     
     95     /* 同步,让线程1先执行 */
     96     usleep(10);
     97     
     98     /* 创建线程pthread2 */
     99     if ((pthread_create(&tidp2, NULL, pthread2, NULL)) == -1)
    100     {
    101         printf("create error!
    ");
    102         return 1;
    103     }
    104     
    105     /* 等待线程pthread1释放 */
    106     if (pthread_join(tidp1, NULL))                  
    107     {
    108         printf("thread is not exit...
    ");
    109         return -2;
    110     }
    111     
    112     /* 等待线程pthread2释放 */
    113     if (pthread_join(tidp2, NULL))                  
    114     {
    115         printf("thread is not exit...
    ");
    116         return -2;
    117     }
    118     
    119     return 0;
    120 }

     代码重点解析:

          进程pthread1和进程pthread2之间单纯用信号量sem同步,无法解决发送线程pthread1,在线程pthread2正在执行命令时,又写入了新的命令的问题,造成命令执行错乱。为了解决这个问题,引入全局变量gIsExecFlag用于同步。经过信号量sem和全局变量gIsExecFlag的完美配合,就可以实现命令发送与执行过程的有序配合。

    测试效果

    编译命令:

    #arm-linux-gcc -o pthread pthread.c -lpthread

    执行结果:

     

    后续分析

          由上图可知,两个线程的整体执行周期,并非是线程pthread1和线程pthread2周期的和,而是取两者中的最大者。实际上,这也很容易想见,两个线程的通信速度,取决于两个线程中速度最慢者,也对应这个结论。

          经过测试,不论发送线程和执行线程的速度孰大孰小,总体的执行结果是一样的,都能保证命令执行流程的正确。所以,就可以证明上述代码的可行性。但是,需要注意的是,线程之间的同步时间还是有限制的,线程pthread1的睡眠时间应≥10ms,否则将会出现执行流程的错误。

    参考资料:Linux线程的信号量同步 

  • 相关阅读:
    Cocos2d-x基础篇C++
    wamp+thinkphp环境配置
    bootstrap table笔记
    写后台SQL的一些心得
    mybatis代码自动生成
    Maven+SpringMVC+MyBatis 上传图片
    五毛的cocos2d-x学习笔记08-动画
    五毛的cocos2d-x学习笔记07-计时器、数据读写、文件读写
    五毛的cocos2d-x学习笔记06-处理用户交互
    学习python笔记 协程
  • 原文地址:https://www.cnblogs.com/amanlikethis/p/5540364.html
Copyright © 2020-2023  润新知