一、基础知识
1、多个进程或线程有可能同时访问的资源(变量、链表、文件等等)称为共享资源, 也叫临界资源(critical resources)。
2、访问这些资源的代码称为临界代码,这些代码区域称为临界区(critical zone)。
3、P操作:程序进入临界区之前必须要对资源进行申请。
4、V操作:程序离开临界区之后必须要释放相应的资源。
二、API
1、semget(获取信号量的ID)
2、semop(对信号量进行P/V操作,或者等零操作)
(1)信号量操作结构体的定义如下
1 struct sembuf 2 { 3 unsigned short sem_num; /* 信号量元素序号(数组下标) */ 4 short sem_op; /* 操作参数 PV 操作 */ 5 short sem_flg; /* 操作选项 */ 6 };
(2)注意:信号量元素的序号从 0 开始,实际上就是数组下标
(3)根据 sem_op 的数值,信号量操作分成 3 种情况:
a、sem_op > 0:表示释放信号量,值的大小表示释放的信号量的个数;
b、sem_op = 0:程序阻塞,直到信号量的值变为0;
c、sem_op < 0:其绝对值表示程序想要获取的信号量的数量,如果此时
sem_num
指定的信号量没有足够的数量,那么程序将阻塞。
3、semctl(获取或者设置信号量的相关属性)
三、步骤
四、代码
1、写数据
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <sys/sem.h>
#include <stdlib.h>
union semun
{
int val; /* 当 cmd 为 SETVAL 时使用 */
struct semid_ds *buf; /* 当cmd为IPC_STAT 或IPC_SET 时使用 */
unsigned short *array; /* 当 cmd 为 GETALL 或 SETALL 时使用 */
struct seminfo *__buf;/* 当 cmd 为 IPC_INFO 时使用 */
};
char * shm_init( void )
{
// 获取key值
int key = ftok("./" , 'X');
// 获取SHM 的ID
int shm_id = shmget(key , 4096 , IPC_CREAT | 0644 );
if (-1 == shm_id )
{
perror("shmget id error");
exit(1); // 直接结束程序(退出进程)
}
// 映射共享内存
char * shm_map = shmat(shm_id , NULL , 0 );
if ((void *) -1 == shm_map)
{
perror("shm map error");
exit(1); // 直接结束程序(退出进程)
}
return shm_map ;
}
int sem_init(void)
{
// 获取一个新的key值
int key = ftok("./" , 'V');
// 获取 信号量的ID
int sem_id = semget(key, 2 , IPC_CREAT | 0644 );
if (-1 == sem_id)
{
perror("sem get id error ");
exit(1);
}
// 初始化信号量的内容 主要是初始化它们的初始的资源数
// 初始化为没有数据 , 有一个空间
union semun set;
set.val = 0 ;
semctl(sem_id , 0, SETVAL , set ); // 初始化数据资源 为 0
set.val = 1 ;
semctl(sem_id , 1, SETVAL , set); // 初始化空间资源 为 1
return sem_id ;
}
int main(int argc, char const *argv[])
{
// 先搞定共享内存并初始化
char * shm_map = shm_init();
// 初始化信号量
int sem_id = sem_init();
// 在写入共享内存之前需要先申请一个空间资源
struct sembuf space ={
.sem_num = 1 , // 需要设置的空间资源的元素下标为 1
.sem_flg = 0 , // 设置标记为 0 啥也不选
.sem_op = -1 // -1 表示资源量即将-1 申请资源
};
struct sembuf data ={
.sem_num = 0 , // 需要设置的空间资源的元素下标为 1
.sem_flg = 0 , // 设置标记为 0 啥也不选
.sem_op = 1 // 1 表示资源量即将加1 释放资源
};
while(1)
{
// 等待空间资源 如果资源暂时不能得到则会阻塞等待(睡眠)
printf("正在等待空间进行写入数据!!!\n");
semop(sem_id , &space , 1 );
printf("已经得到空间, 正在写入数据!!!\n");
printf("请输入需要发送的数据:\n");
fgets(shm_map , 4096 , stdin);
// 设置 数据资源为1
printf("设置数据为 1 \n");
semop(sem_id , &data , 1 );
}
return 0;
}
2、读数据
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <sys/sem.h>
#include <stdlib.h>
union semun
{
int val; /* 当 cmd 为 SETVAL 时使用 */
struct semid_ds *buf; /* 当cmd为IPC_STAT 或IPC_SET 时使用 */
unsigned short *array; /* 当 cmd 为 GETALL 或 SETALL 时使用 */
struct seminfo *__buf;/* 当 cmd 为 IPC_INFO 时使用 */
};
char * shm_init( void )
{
// 获取key值
int key = ftok("./" , 'X');
// 获取SHM 的ID
int shm_id = shmget(key , 4096 , IPC_CREAT | 0644 );
if (-1 == shm_id )
{
perror("shmget id error");
exit(1); // 直接结束程序(退出进程)
}
// 映射共享内存
char * shm_map = shmat(shm_id , NULL , 0 );
if ((void *) -1 == shm_map)
{
perror("shm map error");
exit(1); // 直接结束程序(退出进程)
}
return shm_map ;
}
int sem_init(void)
{
// 获取一个新的key值
int key = ftok("./" , 'V');
// 获取 信号量的ID
int sem_id = semget(key, 2 , IPC_CREAT | 0644 );
if (-1 == sem_id)
{
perror("sem get id error ");
exit(1);
}
// 初始化信号量的内容 主要是初始化它们的初始的资源数
// 初始化为没有数据 , 有一个空间
union semun set;
set.val = 0 ;
semctl(sem_id , 0, SETVAL , set ); // 初始化数据资源 为 0
set.val = 1 ;
semctl(sem_id , 1, SETVAL , set); // 初始化空间资源 为 1
return sem_id ;
}
int main(int argc, char const *argv[])
{
// 先搞定共享内存并初始化
char * shm_map = shm_init();
// 初始化信号量
int sem_id = sem_init();
// 在写入共享内存之前需要先申请一个空间资源
// struct sembuf
// {
// unsigned short sem_num; /* 信号量元素序号(数组下标) */
// short sem_op; /* 操作参数 */
// short sem_flg; /* 操作选项 */
// };
struct sembuf space ={
.sem_num = 1 , // 需要设置的空间资源的元素下标为 1
.sem_flg = 0 , // 设置标记为 0 啥也不选
.sem_op = 1 // 1 表示资源量即将加1 申请资源
};
struct sembuf data ={
.sem_num = 0 , // 需要设置的空间资源的元素下标为 1
.sem_flg = 0 , // 设置标记为 0 啥也不选
.sem_op = -1 // -1 表示资源量即将 减1 释放资源
};
while(1)
{
// 等待数据资源 如果资源暂时不能得到则会阻塞等待(睡眠)
printf("正在等待数据的到达!!!\n");
semop(sem_id , &data , 1 );
printf("数据已经到达!!!\n");
printf("Jack 说:%s\n" , shm_map );
// fgets(shm_map , 4096 , stdin);
// 设置 空间资源为1
sleep(2);
printf("数据处理结束 , 设置空间为 1 !!!\n");
semop(sem_id , &space , 1 );
}
return 0;
}