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

2015-3-9 15:31 1411 17 17 分类: 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;
}
 
PARTNER CONTENT

文章评论0条评论)

登录后参与讨论
EE直播间
更多
我要评论
0
17
关闭 站长推荐上一条 /3 下一条