IPC键值获得:
key_t ftok( const char * fname, int id )
fname:文件地址; id: 0-255自定义; 返回IPC键值。不同进程可用同样的方式获得相同的键值,以便semget,shmget,smgget使用。
int semget(key_t key, int nsems, int semflg);
key: ftok获得的键值;nsems信号量的个数;semflg:IPC_CREAT | 0666(创建,可读写);返回,信号量的描述符,信号量个数为nsems。
union semun_u
{
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
};
int semctl(int semid,int semnum,int cmd, /*union semun arg*/);
semid:semget获得的fd;semnum:操作第几个信号量(0为第一个);cmd:命令如SETVAL(设置该信号量semval值,用于阻塞。需要:semun_u.val(=1)),GETVAL,IPC_RMID(删除);返回-1错误。注意:semctl两个进程不要都用这个函数来初始化SETVAL(设置一个即可),否则出错。
int semop(int semid, struct sembuf *sops, unsigned nsops);
semid;sops如下结构;nsops:操作sops的个数。
而int semget(key_t key, int nsems, int semflg);需要的key可以用ftok得到。
共享内存操作:
创建共享内存:
ftok,
shmget,
shmat(映射内存地址),
创建信号量:
ftok,
semget(一般配置1个信号量)
semctl(配置某一个编号信号量的值(临界资源数),PV操作(百度百科))
如果是互斥信号量的话,应该设置信号量Sem=1,但是当有5个进程都访问的话,最后在该信号量的链表里会有4个在等待,也是说S=-4,那么第一个进程执行了V操作使S加1,释放了资源,下一个应该能够执行,但唤醒的这个进程在执行P操作时因S〈0,也还是执行不了,这是怎么回事呢?当一个进程阻塞了的时候,它已经执行过了P操作,并卡在临界区那个地方。当唤醒它时就立即进入它自己的临界区,并不需要执行P操作了,当执行完了临界区的程序后,就执行V操作
注意系统调用semctl中的最后一个参数是一个联合类型的副本,而不是一个指向联合类型的指针。
需要注意的是,对于semun联合体,最好自己定义,否则GCC编译器可能会报“semun大小未知”。
while(1)
{
semop(nSemID, &((sembuf)({0, -1, SEM_UNDO})), 1)//semop(信号量-1,),SEM_UNDO表示本进程挂掉,信号量恢复之前的值,防止资源锁死。
操作shmat返回地址,
semop(nSemID, &((sembuf)({0, +1, SEM_UNDO})), 1)信号量+1
}
shmdt;
shmctl(lShareMemID, IPC_RMID, NULL);//注:如果在此之前程序崩溃,共享内存将不会被释放。
if(-1 != SemID)
{
semctl(SemID, 0, IPC_RMID, unSemArg);//释放
}
union
{
int a;
char b[10];
}
a="ab",b[0]=b,b[1]=a
大小>最大成员,并且是最大类型的整数倍。这个=12
key_t ftok( const char * fname, int id );
fname文件地址,id:1-255但是我测试有些数据不可以。返回-1错误,否则返回其他int型,包括负数。
int shmget(key_t key, size_t size, int shmflg);
开辟内存;key由ftok生成;size:空间大小;shmflg=IPC_CREAT | 0666:表示不存在创建IPC描述符,存在得到相应IPC描述符;返回-1错误。
void *shmat(int shmid, const void *shmaddr, int shmflg);
映射空间;shmid:IPC描述符;shmaddr:NULL系统分配地址;shmflg:除了0x10000(SHM_RDONLY)为读写,直接=0。
此后操作返回的地址就可以了。
使用int shmctl(shmid,IPC_RMID, NULL)删除共享内存;和int shmdt(const void *shmaddr);断开与共享内存的映射。参考
if(NULL != shmAddr)
{
shmdt(shmAddr);
if(shmIPCid > 0)
{
shmctl(shmIPCid, IPC_RMID, NULL);
}
}
int semget(key_t key, int nsems, int semflg);
创建信号量。nsems信号量数组个数,shmflg=IPC_CREAT | 0666没有旧创建,有直接返回描述符。返回-1错误,(注:也判断0也不能用,测试一些ftok中id配置不对,这里返回0,导致信号量不能锁住。)
int semctl(int semid,int semnum,int cmd, /*union semun arg*/);
semid描述符;semnum:操作信号数组的第几个,0开始;cmd=SETVAL是设置:semun->val的。这里的val我目前的猜测应该时信号量可通过的数量,如val=2,使用semop阻塞的时候可以同时通过两个。一般设置为1。
semctl(semIPCid, SEM_SHARE_MEM_NUM, IPC_RMID, tempsemun/*val=0*/);删除信号量。
int semop(int semid, struct sembuf *sops, unsigned nsops);//一直阻塞
int semtimedop(int semid, struct sembuf *sops, unsigned nsops, struct timespec *timeout);//超时返回-1
semid描述符;sops->sem_op=-1进入使用,+1出去使用,sops->sem_flg=SEM_UNDO;nsops操作多少个信号量,从sops->sem_flg开始计数,1个=1;timeout配置超时时间;
struct sembuf
{
unsigned short sem_num; /* semaphore number */操作信号数组的第几个,0开始
short sem_op; /* semaphore operation */-1表示阻塞多一,+1表示阻塞减一。
short sem_flg; /* operation flags */ = SEM_UNDO表示本进程挂掉,信号量恢复之前的值,防止资源锁死。
};
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <fcntl.h>
#include <iostream>
#include "shm_sem_info.h"
using namespace std;
static int readSemFileOk()
{
FILE *fd;
int tempi = 0;
fd = fopen(SEMAPHORE_SETVALUE_PATH, "r");
if(NULL == fd)
{
printf("surpas:%s,%d,fd not exist;\n", __FILE__, __LINE__);
if(fd = fopen(SEMAPHORE_SETVALUE_PATH, "w"))
{
fclose(fd);
return 1;
}
printf("ERROR -- surpas:%s,%d,fd not exist;\n", __FILE__, __LINE__);
return -1;
}
//fscanf(fd,"file%dfile",&tempi);
//printf("surpas:%s,%d, tempi = %d;\n", __FILE__, __LINE__, tempi);
//if(1 == tempi)
//{
//fprintf(fd,"1");
// return 0;
//}
//else
//{
// fprintf(fd,"file1file");
// return 1;
//}
fclose(fd);
return 0;
}
static void resetSemFileValue()
{
remove(SEMAPHORE_SETVALUE_PATH);
}
shmSemFile::shmSemFile()
{
shmKeyID = -1;
semKeyID = -1;
shmIPCid = -1;
semIPCid = -1;
shmAddr = NULL;
}
shmSemFile::~shmSemFile()
{
deleteShareMem();
deleteSemaphore();
resetSemFileValue();
}
void* shmSemFile::createShareMemery()
{
shmKeyID = ftok(IPC_FILE_PATH, IPC_FTOK_ID);
if(-1 == shmKeyID)
{
return NULL;
}
cout<<"surpas:"<<__FILE__<<","<<__LINE__<<",ftok="<<shmKeyID<<endl;
shmIPCid = shmget(shmKeyID, SHARE_MEM_SIZE, IPC_CREAT | 0666);
if(-1 == shmIPCid)
{
return NULL;
}
printf("surpas:%s,%d,shmIPCid=%d;\n", __FILE__, __LINE__, shmIPCid);
shmAddr = shmat(shmIPCid, NULL, 0);
if((void *)-1 == shmAddr)
{
return NULL;
}
printf("surpas:%s,%d,shmAddr=%p;\n", __FILE__, __LINE__, shmAddr);
return shmAddr;
}
int shmSemFile::createSemaphore()
{
semKeyID = ftok(IPC_SEM_FILE_PATH, IPC_FTOK_ID);//IPC_SEM_FILE_PATH
if(-1 == semKeyID)
{
printf("surpas:%s,%d,shmKeyID=%d\n", __FILE__, __LINE__, semKeyID);
return -1;
}
cout<<"surpas:"<<__FILE__<<","<<__LINE__<<",ftok="<<semKeyID<<endl;
semIPCid = semget(semKeyID, SEMAPHORE_TOTAL_NUM, IPC_CREAT | 0666);
if(-1 == semIPCid)
{
return -2;
}
printf("surpas:%s,%d,semIPCid=%d;\n", __FILE__, __LINE__, semIPCid);
if(1 == readSemFileOk())//两个进程不能都设置SETVAL
{
union semun_u tempsemun;
int tempflag;
tempsemun.val = 1;
tempflag = semctl(semIPCid, SEM_SHARE_MEM_NUM, SETVAL, tempsemun);
//tempflag = semctl(semIPCid, SEM_SHARE_MEM_NUM, GETVAL);
printf("surpas:%s,%d,%d\n", __FILE__, __LINE__,tempflag);
if(-1 == tempflag)
{
return -3;
}
}
return 1;
}
int shmSemFile::semLock()
{
int tempflag;
struct sembuf tempsembuf = {0, -1, SEM_UNDO};
struct timespec tempOutTime = {1, 0};
tempflag = semop(semIPCid, &tempsembuf, 1);//sussed return 0
//tempflag = semtimedop(SEM_SHARE_MEM_NUM, &tempsembuf, 1, &tempOutTime);//sussed return 0
if(-1 == tempflag)
{
return -1;
}
tempflag = semctl(semIPCid, SEM_SHARE_MEM_NUM, GETVAL);
return 0;
}
int shmSemFile::semUnlock()
{
int tempflag;
struct sembuf tempsembuf = {0, +1, SEM_UNDO};
struct timespec tempOutTime = {1, 0};
tempflag = semop(semIPCid, &tempsembuf, 1);//sussed return 0
//tempflag = semtimedop(SEM_SHARE_MEM_NUM, &tempsembuf, 1, &tempOutTime);//sussed return 0
printf("surpas:%s,%d,semtimedop=%d;\n", __FILE__, __LINE__, tempflag);
if(-1 == tempflag)
{
return -1;
}
return 0;
}
int shmSemFile::readShareMem()
{
}
int shmSemFile::getShareMem()
{
}
void shmSemFile::deleteShareMem()
{
if(NULL != shmAddr)
{
shmdt(shmAddr);
printf("surpas:%s,%d,shmAddr=%p;\n", __FILE__, __LINE__, shmAddr);
if(shmIPCid > 0)
{
shmctl(shmIPCid, IPC_RMID, NULL);
}
}
}
void shmSemFile::deleteSemaphore()
{
union semun_u tempsemun;
tempsemun.val = 0;
if(semIPCid > 0)
{
semctl(semIPCid, SEM_SHARE_MEM_NUM, IPC_RMID, tempsemun);
}