原创 Linux进程间通信:信号互斥编程

2015-3-9 15:31 550 0 分类: MCU/ 嵌入式 文集: Linux应用程序开发学习
信号量(又名:信号灯)与其他进程间通信方式不大相同,主要用途是保护临界资源(进程互斥)。进程可以根据它判定是否能够访问某些共享资源。除了用于访问控制外,还可用于进程同步。
信号量的分类:
  1. 二值信号灯:信号灯的值只能取0或1
  2. 计数信号灯:信号灯的值可以取任意非负值。
信号量的实质:1、数字  2、操作,包括释放和获取两种情况。
 

8.1 创建/ 打开信号量集合

8.1.1 函数名     semget
8.1.2 函数原形     int semget(key_t key, int nsems, int sem***);
8.1.3 函数功能     获取信号量集合的标识符
8.1.4 所属头文件     <sys/types.h>  <sys/ipc.h>  <sys/sem.h>
8.1.5 返回值    成功:返回信号量集合的标识符  失败:-1 
8.1.6 参数说明
     key:键值  sem***:标志,可以取IPC_CREAT  nsems:创建的这个信号量集合里面包含的信号量的数目
8.1.7 范例代码
 

8.2 操作信号量

8.2.1 函数名     semop
8.2.2 函数原形     int semop(int semid, struct *sops, unsigned nsops, struct timespec *timeout);
8.2.3 函数功能     操作信号量集里面的信号量
8.2.4 所属头文件     <sys/types.h>  <sys/ipc.h>  <sys/sem.h>
8.2.5 返回值     成功:返回0  失败:返回-1
8.2.6 参数说明     semid:要操作的信号量集合的标识符  nsops:要操作多少个信号量  sops:堆信号量执行什么样的操作,实则sops包含了下面这个结构体:其中sem_num:指定了是信号量集合的第几个信号量。sem_op:若sem_op为n。n>0则表示释放了n个信号量。n<0则表示获取了n个信号量

8.3 信号量的控制

8.3.1 函数名     semctl
8.3.2 函数原形     int semctl(int semid, int semnum, int cmd, ...);
8.3.3 函数功能     控制信号量
8.3.4 所属头文件     <sys/types.h>  <sys/ipc.h>  <sys/sem.h>
8.3.5 返回值     成功:根据cmd返回不同的非负值  失败:-1
8.3.6 参数说明     semid:信号量集合的标识符 semnum:信号量集合的哪个信号量  cmd:相应的控制命令(GETVAL:返回成员semnum的semval值, SETVAL:设置成员semnum的semval值。该值由arg.val指定)。
 

8.4 获取key值

8.4.1 函数名     ftok
8.4.2 函数原形     key_t ftok(const char *pathname, int proj_id);
8.4.3 函数功能     将路径名和项目标识符转化为一个进程间信号量通信的key值
8.4.4 所属头文件     <sys/types.h>  <sys/ipc.h>
8.4.5 返回值    成功:key值将被返回  失败:-1 
8.4.6 参数说明     pathname:路径名  proj_id:自定义的数字id
 
小实验:假设有这样的场景:数学课代表A要在公示栏上写“math cancel”这样一个通知。当他写完“math”后,电话铃响了。然后出去接了个电话。正在这时英语课代表B也要写通知,通知内容是“English exam”。这时公示栏上的内容是“math English exam”。B写完后,A又不管三七二十一的写上了“cancel”。这时黑板上的内容为“math English exam cancel”。从而引起了歧义。代码如下:
 
astudent.c:
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h> 
#include<fcntl.h>
int main()
{
     int fd;
     fd = open("/home/board.txt",O_RDWR|O_APPEND);//读取txt文件
     write(fd, "math", 5);
     sleep(3);
     write(fd, " cancel", 7);
     close(fd);
     return 0;
}
bstudent.c:
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h> 
#include<fcntl.h>

int main()
{
     int fd;
     fd = open("/home/board.txt",O_RDWR|O_APPEND);//读取txt文件
     write(fd, "English exam", 13);
     return 0;
}
公示栏上的内容为下图:
 
那么,怎样消除这样的问题呢?我们可以看出这两个事件是互斥的。我们可以通过设置一个信号量来解决。当A开始写通知的时候生成一个标志位。直至A写完通知,标志位状态改变,B开始写通知。
 
#include<stdio.h>
#include<sys/types.h> 
#include<sys/stat.h>  
#include<fcntl.h>
#include<sys/types.h>  
#include<sys/ipc.h>  
#include<sys/sem.h>

int main()
{
     int fd = 0;
     int semid;
     key_t key;
     struct sembuf sops;
     int ret;

     key = ftok("/home", 1);
     semid = semget(key, 1, IPC_CREAT);
     semctl(semid, 0, SETVAL, 1);

     fd = open("/home/board.txt",O_RDWR|O_APPEND);//读取txt文件
     
     sops.sem_num = 0;
     sops.sem_op = -1;
     semop(semid, &sops, 1);

     
     write(fd, "math", 5);
     sleep(10);
     write(fd, " cancel", 7);

     sops.sem_num = 0;
     sops.sem_op = 1;
     semop(semid, &sops, 1);

     close(fd);
     return 0;
}
 
#include<stdio.h>
#include<sys/types.h> 
#include<sys/stat.h>  
#include<fcntl.h>
#include<sys/types.h>  
#include<sys/ipc.h>  
#include<sys/sem.h>

int main()
{
     int fd = 0;
     int semid;
     key_t key;
     struct sembuf sops;
     int ret;

     key = ftok("/home", 1);
     semid = semget(key, 1, IPC_CREAT);

     fd = open("/home/board.txt",O_RDWR|O_APPEND);//读取txt文件

     sops.sem_num = 0;
     sops.sem_op = -1;
     semop(semid, &sops, 1);
     
     write(fd, "English exam", 13);

     sops.sem_num = 0;
     sops.sem_op = 1;
     semop(semid, &sops, 1);

     close(fd);
     return 0;
}
 
广告

文章评论 0条评论)

登录后参与讨论
相关推荐阅读
潇洒哥 2015-07-08 16:01
位操作符的使用技巧
在C语言编程中,数据的位是可以操作的最小数据单位,理论上可以用“位运算”来完成所有的运算和操作。一般的位操作是用来控制硬件的,或者做数据变换使用,但是,灵活的位操作可以有效地提高程序运行的效...
潇洒哥 2015-04-04 17:39
finish shell分析之底层usart
rt_thread的finsh shell系统不愧是调试的一项利器,它可以除了完成一般shell的功能外,甚至还可以自定义命令。这个对功能单一的嵌入式系统来说是十分可贵的。在此我并不想对finsh...
潇洒哥 2015-04-01 21:29
__main() 和 main()
因为我们通常在BOOTLOADER中都已做好了比较细致的初始化工作,包括代码的搬运,所以我们最好别再调用库函数__main(),因为__main()作为ADS集成好的库函数,会对系统进行初始化设置...
潇洒哥 2015-03-26 22:54
RT-Thread学习之scons篇--解析rtconfig.py文件
rtconfig.py文件,主要用于指定编译器以及安装路径。除此之外,该文件中定义了大量的变量,这些变量包括编译选项,汇编选项,链接选项。   import os # toolchain...
潇洒哥 2015-03-26 22:53
RT-Thread学习之scons篇--SConsruct脚本文件解析
       scons的构建文件名称是统一的都称为SConstruct。其是scons所接受的编译脚本主文件。当然为了方便目录的组织,也允许在各个目录下面存放SConscript, 然后最上面S...
潇洒哥 2015-03-26 22:53
RT-Thread学习之scons篇--SConcript文件解析
SConscript文件是用来指定哪些文件会加入编译。先来分析下BSP主目录下的SConscript文件: import rtconfig Import('RTT_ROOT') fro...
广告
我要评论
0
0
广告
关闭 热点推荐上一条 /2 下一条