首先,我们在一般的基础上,不同进程访问同一内存,即共享内存的前提上加入信号量,两者比对看,前者可能售卖同一张票,即两个进程同时访问共享内存,加入信号量就是为了杜绝这种情况的发生,因为信号量就是为了防止出现因多个程序同时访问一个共享资源而引发的一系列问题,我们需要一种方法,它可以通过生成并使用令牌来授权,在任一时刻只能有一个执行进程访问代码的临界区域。临界区域是指执行数据更新的代码需要独占式地执行。而信号量就可以提供这样的一种访问机制,让一个临界区同一时间只有一个进程在访问它,也就是说信号量是用来调协进程对共享资源的访问的。下面是两者的代码
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <string.h>
#include <time.h>
typedef struct _shm
{
int flag;
int ticket;
}SHM;
int sellTicket(SHM* pshm)
{
while(1)
{
int time =rand()%10 + 1;
usleep(time*100000);
if(pshm->flag == 1)
{
pshm->flag = 0;
if(pshm->ticket == 0)
{
pshm->flag = 1;
break;
}
printf("卖掉一张票,座位号:%d\n",pshm->ticket);
pshm->ticket--;
pshm->flag =1;
}
}
}
int main(int argc, char** argv)
{
//获取时间
srand((unsigned int)time(NULL));
//创建或者获取一个共享内存
int shimd = shmget((key_t)1024,sizeof(SHM),0666|IPC_CREAT);
if(shimd == -1)
{
perror("shmget");
return -1;
}
//将共享内存映射到当前的进程空间
SHM* pshm = (SHM*)shmat(shimd,NULL,0);
if(pshm == (SHM*)-1)
{
perror("shmat");
return -1;
}
//如果命令行参数等于2,负责对共享内存进行初始化
if(argc == 2)
{
pshm->flag = 1;
pshm->ticket = 100;
}
//开始卖票
sellTicket(pshm);
/*strcpy(pshm->msg,"hello");
//解除功能共享内存映射,解除是当前进程不能再使用该共享内存 ,不是删除
shmdt(pshm);*/
//对共享内存进行删除
if(argc == 2)
{
shmctl(shimd,IPC_RMID,NULL);
}
return 0;
}
下面是改进版,首先是.h文件
#ifndef __SEMAPH_H__
#define __SEMAPH_H__
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
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) */
};
//信号量的初始化函数
int sem_init(int sem_id)
{
union semun sem;
sem.val = 1;
int ret = semctl(sem_id,0,SETVAL,sem);
return ret;
}
//信号量 P 操作
int sem_p(int sem_id)
{
struct sembuf sem;
sem.sem_num = 0;
sem.sem_op = -1;
sem.sem_flg = SEM_UNDO;
int ret = semop(sem_id,&sem,1);
return ret;
}
//信号量 V 操作
int sem_v(int sem_id)
{
struct sembuf sem;
sem.sem_num = 0;
sem.sem_op = 1;
sem.sem_flg = SEM_UNDO;
int ret = semop(sem_id,&sem,1);
return ret;
}
//销毁信号量
int sem_del(int sem_id)
{
int ret = semctl(sem_id,0,IPC_RMID);
return ret;
}
#endif
正文
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <string.h>
#include <time.h>
#include "semaph.h"
typedef struct _shm
{
int flag;
int ticket;
}SHM;
int sellTicket(SHM* pshm,int sem_id)
{
while(1)
{
int time =rand()%10 + 1;
usleep(time*100000);
//信号量的P操作
sem_p(sem_id);
if(pshm->ticket == 0)
{
sem_v (sem_id);
break;
}
printf("卖掉一张票,座位号:%d\n",pshm->ticket);
pshm->ticket--;
//V操作
sem_v(sem_id);
}
}
int main(int argc, char** argv)
{
//获取时间
srand((unsigned int)time(NULL));
//创建或者获取一个共享内存
int shimd = shmget((key_t)1024,sizeof(SHM),0666|IPC_CREAT);
if(shimd == -1)
{
perror("shmget");
return -1;
}
//创建一个信号量
int sem_id =semget((key_t)2048,1,0666|IPC_CREAT);
if(sem_id == -1)
{
perror("semget");
return -1;
}
//将共享内存映射到当前的进程空间
SHM* pshm = (SHM*)shmat(shimd,NULL,0);
if(pshm == (SHM*)-1)
{
perror("shmat");
return -1;
}
//如果命令行参数等于2,负责对共享内存和信号量进行初始化
if(argc == 2)
{
sem_init(sem_id);
pshm->ticket = 100;
}
//开始卖票
sellTicket(pshm,sem_id);
//对共享内存和信号量进行删除
if(argc == 2)
{
shmctl(shimd,IPC_RMID,NULL);
sem_init(sem_id);
}
return 0;
}