shm sem msg

IPC(interprocess communication)概念.进程通讯如shm,sem,smg.

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的个数。

struct sembuf
{
unsigned short sem_num; /* semaphore number */第几个信号量0开始
short sem_op; /* semaphore operation */-1P操作,+1V操作。
short sem_flg; /* operation flags */SEM_UNDO(崩溃还原以前的semval)等标志
};


而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);
    }



你可能感兴趣的:(shm sem msg)