在上篇中我们讲到了共享内存的操作,没有看的童鞋可以点击链接:
Linux共享内存的使用(一)
信号量
信号量是一个内存变量,可以被系统中的任何进程所访问。
为什么引入信号量
大家可以考虑这个问题...
在使用共享内存的时候,如果客户端在读取数据时,恰好服务器端也在写数据,那么就会出现问题。
如何解决呢?
出现读写冲突的问题,可通过信号量机制,保证读写共享内存段互斥进行加以解决。
linux中的信号量
Linux中信号量是以集合的形式存在的,一个集合中存在着多个信号量。
信号量的操作函数
功能 创建一个信号量集合
头文件 #include<sys/sem.h>
函数原型
int semget(key_t key, int nsems, int flag);
key 创建信号量集的键值
nsems 集合中信号量的个数
flag 信号量集的权限
返回值 >0 信号量集的ID
-1 失败
功能 操作信号量集合
头文件 #include<sys/sem.h>
函数原型
int semctl(int semid, int semnum, int cmd, union semun arg);
semid 信号量集ID
semnum 要操作的信号量序号
cmd 要执行的命令
IPC_STAT 取信号量集的属性,存放在arg.buf所指单元
IPC_SET 按arg.buf所指单元的数据设置信号量集合中的
sem_perm.uid、sem_perm.gid、sem_perm.mode
三个属性。
IPC_RMID 删除该信号量集合
GETVAL 返回第semnum个信号量的semval值
SETVAL 用arg.val设置第semnum个信号量的semval值
GETALL 取信号量集所有信号量的值,存放在arg.array指向的
数组中
SETALL 按照arg.array所指数组的值设置信号量集中所有信号
量的值
arg 修改信号量时所需的数据或获取信号量数据时所需的变
量(可选)
返回值 与cmd相关
功能 完成信号量集的一组操作
头文件 #include<sys/sem.h>
函数原型
int semop(int semid, struct sembuf semoparr[], size_t
nops);
semid 信号量集ID
semoparr 存放一组信号量操作的数组
nops 数组中操作的数量
返回值 0 成功
-1 失败
我们直接在上篇的基础上,对服务器的代码进行一些修改,客户端代码不变
//服务器端代码
#include <stdio.h>
#include <stdlib.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <time.h>
#include <string.h>
#include <unistd.h>
#define SHM_KEY 99
#define SEM_KEY 88
int init_sem(int semid,int semnum,int val){
union semun{
int val;
struct semid_ds *buf;
unsigned short *array;
}initval;
initval.val=val;
if(semctl(semid,semnum,SETVAL,initval)==-1) {
perror("semctl");
exit(1);
}
}
void lockforwrite(int semid){
struct sembuf action[2];
//等待所有的读进程都完成(进行写操作前要保证没有读进程执行)
action[0].sem_num=0;
action[0].sem_flg=SEM_UNDO;
action[0].sem_op=0;
//进行写操作(申请资源)
action[1].sem_num=1;
action[1].sem_flg=SEM_UNDO;
action[1].sem_op=-1;
if(semop(semid,action,2)==-1) {
perror("semop");
exit(1);
}
}
void unlockafterwrite(int semid){
struct sembuf action[1];
//释放写操作资源
action[0].sem_num=1;
action[0].sem_flg=SEM_UNDO;
action[0].sem_op=+1;
if(semop(semid,action,1)==-1) {
perror("semop");
exit(1);
}
}
int main()
{
int seg_id,sem_id;
char *mem_ptr;
time_t now;
int i=30;
seg_id=shmget(SHM_KEY,100,IPC_CREAT|0777);
if(seg_id==-1)
{
perror("shmget");
exit(1);
}
mem_ptr=(char *)shmat(seg_id,0,0);
if(mem_ptr==NULL)
{
perror("shmat");
exit(1);
}
//(1)创建信号量集
if((sem_id=semget(SEM_KEY,2,IPC_CREAT|0770))==-1){
perror("semget");
exit(1);
}
//(2)对信号量进行初始化
init_sem(sem_id, 0, 0);
init_sem(sem_id, 1, +1);
while(i>0)
{
time(&now);
puts(ctime(&now));
//(3)对写操作加锁
lockforwrite(sem_id);
strcpy(mem_ptr,ctime(&now));
//(4)解锁
unlockafterwrite(sem_id);
sleep(1);
i--;
}
shmctl(seg_id,IPC_RMID,NULL);
return 0;
}