进程通信的概念请参考上一篇文章:Linux进程间通信之共享内存。
信号量作用:用于进程/线程同步或互斥的机制。
信号量主要用于控制多个进程间或一个进程内的多个线程间对共享资源的访问, 相当于内存中的标志,进程可以根据它判定是否能够访问某些共享资源,同时,进程也可以修改该标志,除了用于共享资源的访问控制外,还可用于进程同步。
包含头文件:
#include
semget ()创建信号量:
int semget(key_t key, int num_sems, int sem_flags);
semctl()初始化信号量:
int semctl(int sem_id, int sem_num, int command, …);
union semun {union semun {
int val; /* Value for SETVAL *///信号量初始值
struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */
unsigned short *array; /* Array for GETALL, SETALL */
struct seminfo *__buf; /* Buffer for IPC_INFO (Linux-specific) */
};
semop()操作信号量值PV:
int semop(int sem_id, struct sembuf * sops, size_t nsops);
struct sembuf
{
short sem_num;/*信号量的编号*/
short sem_op;/*P操作为-1,V操作为1*/
short sem_flg;/*0标识阻塞方式,IPC_NOWAIT非阻塞*/
}
信号量用于同步,步骤如下:
实验目的:进程A接收到串口信息,向进程B发送信号量;B接收到信号量打印“sem wait ok”。
实验代码:
a.c
#include
#include
#include
#include
#include
union semun
{
int val; /* Value for SETVAL */
struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */
unsigned short *array; /* Array for GETALL, SETALL */
struct seminfo *__buf; /* Buffer for IPC_INFO(Linux-specific) */
};
static int semid = 0;
int semInit(void)
{
semid = semget((key_t)0x1234,1,IPC_CREAT | 0600);
if(semid == -1)
{
printf("semget error");
return -1;
}
union semun a;
a.val = 0;//初始化信号量的值为0
if(semctl(semid,0,SETVAL,a)==-1)
{
perror("semctl init error");
return -1;
}
return 0;
}
int semPost(void)
{
struct sembuf buf;
buf.sem_num = 0;//信号量下标,semget中信号量的数量初始化为1,此处只能为0
buf.sem_op = 1;//V操作
buf.sem_flg = SEM_UNDO;
if(semop(semid,&buf,1)==-1)//1表示操作数,sembuf的数量
{
perror("p error");
return -1;
}
return 0;
}
int semWait(void)
{
struct sembuf buf;
buf.sem_num = 0;
buf.sem_op = -1;//P操作
buf.sem_flg = SEM_UNDO;
if(semop(semid,&buf,1)==-1)
{
perror("v error");
return -1;
}
return 0;
}
int semDestroy(void)
{
if(semctl(semid,0,IPC_RMID)==-1)//0代表信号量集
{
perror("semctl destroy error");
return -1;
}
return 0;
}
int main()
{
char shmptr[100];
semInit();
while(1)
{
printf("input:");
scanf("%s",shmptr);
semPost();
}
}
b.c
#include
#include
#include
#include
#include
union semun
{
int val; /* Value for SETVAL */
struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */
unsigned short *array; /* Array for GETALL, SETALL */
struct seminfo *__buf; /* Buffer for IPC_INFO(Linux-specific) */
};
static int semid = 0;
int semInit(void)
{
semid = semget((key_t)0x1234,1,IPC_CREAT | 0600);
if(semid == -1)
{
printf("semget error");
return -1;
}
union semun a;
a.val = 0;//初始化信号量的值为0
if(semctl(semid,0,SETVAL,a)==-1)
{
perror("semctl init error");
return -1;
}
return 0;
}
int semPost(void)
{
struct sembuf buf;
buf.sem_num = 0;//信号量下标,semget中信号量的数量初始化为1,此处只能为0
buf.sem_op = 1;//V操作
buf.sem_flg = SEM_UNDO;
if(semop(semid,&buf,1)==-1)//1表示操作数,sembuf的数量
{
perror("p error");
return -1;
}
return 0;
}
int semWait(void)
{
struct sembuf buf;
buf.sem_num = 0;
buf.sem_op = -1;//P操作
buf.sem_flg = SEM_UNDO;
if(semop(semid,&buf,1)==-1)
{
perror("v error");
return -1;
}
return 0;
}
int semDestroy(void)
{
if(semctl(semid,0,IPC_RMID)==-1)//0代表信号量集
{
perror("semctl destroy error");
return -1;
}
return 0;
}
int main()
{
semInit();
while(1)
{
semWait();
printf("sem wait ok\r\n");
}
}
测试现象:
gcc a.c -o a
gcc b.c -o b
信号量用于互斥入下图所示,进程B在访问x资源时,此时进程A无法访问;进程A访问x资源时,此时进程B无法访问。可防止资源访问冲突。
步骤如下:
实验目的:进程A在串口打印的过程中,进程B不能访问不能使用串口;等待A进程打印完成后,B的串口打印才得到运行。
实验代码:
a.c
#include
#include
#include
#include
#include
union semun
{
int val; /* Value for SETVAL */
struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */
unsigned short *array; /* Array for GETALL, SETALL */
struct seminfo *__buf; /* Buffer for IPC_INFO(Linux-specific) */
};
static int semid = 0;
int semInit(void)
{
semid = semget((key_t)0x1234,1,IPC_CREAT | 0600);
if(semid == -1)
{
printf("semget error");
return -1;
}
union semun a;
a.val = 1;//初始化信号量的值为1
if(semctl(semid,0,SETVAL,a)==-1)
{
perror("semctl init error");
return -1;
}
return 0;
}
int semPost(void)
{
struct sembuf buf;
buf.sem_num = 0;//信号量下标,semget中信号量的数量初始化为1,此处只能为0
buf.sem_op = 1;//V操作
buf.sem_flg = SEM_UNDO;
if(semop(semid,&buf,1)==-1)//1表示操作数,sembuf的数量
{
perror("p error");
return -1;
}
return 0;
}
int semWait(void)
{
struct sembuf buf;
buf.sem_num = 0;
buf.sem_op = -1;//P操作
buf.sem_flg = SEM_UNDO;
if(semop(semid,&buf,1)==-1)
{
perror("v error");
return -1;
}
return 0;
}
int semDestroy(void)
{
if(semctl(semid,0,IPC_RMID)==-1)//0代表信号量集
{
perror("semctl destroy error");
return -1;
}
return 0;
}
int main()
{
semInit();
for(int i=0;i<10;i++)
{
semWait();
printf("A1\r\n");
sleep(1);
printf("A2\r\n");
semPost();
}
}
b.c
#include
#include
#include
#include
#include
union semun
{
int val; /* Value for SETVAL */
struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */
unsigned short *array; /* Array for GETALL, SETALL */
struct seminfo *__buf; /* Buffer for IPC_INFO(Linux-specific) */
};
static int semid = 0;
int semInit(void)
{
semid = semget((key_t)0x1234,1,IPC_CREAT | 0600);
if(semid == -1)
{
printf("semget error");
return -1;
}
union semun a;
a.val = 0;//初始化信号量的值为0
if(semctl(semid,0,SETVAL,a)==-1)
{
perror("semctl init error");
return -1;
}
return 0;
}
int semPost(void)
{
struct sembuf buf;
buf.sem_num = 0;//信号量下标,semget中信号量的数量初始化为1,此处只能为0
buf.sem_op = 1;//V操作
buf.sem_flg = SEM_UNDO;
if(semop(semid,&buf,1)==-1)//1表示操作数,sembuf的数量
{
perror("p error");
return -1;
}
return 0;
}
int semWait(void)
{
struct sembuf buf;
buf.sem_num = 0;
buf.sem_op = -1;//P操作
buf.sem_flg = SEM_UNDO;
if(semop(semid,&buf,1)==-1)
{
perror("v error");
return -1;
}
return 0;
}
int semDestroy(void)
{
if(semctl(semid,0,IPC_RMID)==-1)//0代表信号量集
{
perror("semctl destroy error");
return -1;
}
return 0;
}
int main()
{
int i;
semInit();
for(i=0;i<10;i++)
{
semWait();
printf("B1\r\n");
sleep(1);
printf("B2\r\n");
semPost();
}
}
测试现象:
A在打印时,B不能执行打印;B在打印时,A不能执行打印。
查看系统中的IPC:ipcs
删除系统中的共享内存段:ipcrm -m [id]
删除系统中的信号量标志:ipcrm –s [id]