linux环境创建信号灯失败,关于linux信号灯操作(包括回滚)例子及其说明

unix或linux实现P,V操作,主要是通过信号等操作来实现。

信号灯的创建和获取通过调用semget函数来实现 例如mysem_id=semget(SEM_KEY,SEMSIZE,IPC_CREAT|0666)),其中SEM_KEY为欲创建或调用的信号灯的键值,可以自己定义  比如#define  SEM_KEY 7589    ,SEMSIZE 为信号等的数量,semget实际是得到一个信号灯数组,这个数组的长度可以自己定义 #define SEMSIZE 5  这样就得到了一个信号灯数量为5的信号灯数组。创建或取得信号等数组后,可以对各个信号灯进行赋值。一下为赋值函数

/**

* s_id 第s_id个信号灯

* ini_value  初始值

*/

void init_mysemvalue(int s_id,int ini_value)

{

key_t    key;

int i;

struct sembuf    op;

union semun        arg;

//    op.sem_num    =    s_id;

op.sem_op    =    1;

op.sem_flg    =    0;

//    key=ftok(PATHNAME,'O');

if(mysem_id == -1){

if((mysem_id=semget(SEM_KEY,SEMSIZE,IPC_CREAT|0666))==-1){

perror("semget err!\n");

exit(-1);

}

}

/*arg.array = (unsigned short *) calloc(SEMSIZE,sizeof(unsigned short));

if(arg.array == NULL){

printf("No enough memory to calloc!\n");

exit(-1);

}

arg.array[s_id]    =    ini_value;*/

arg.val = ini_value;

if(semctl(mysem_id,s_id,SETVAL,arg) == -1){

perror("semctl err:");

exit(-1);

}

}

其中 union semun 的定义为

union semun{

int     val;

struct semid_ds *buf;

unsigned short *array;

};

取得指定的信号等的当前值

int  getmysemvalue(int s_id)

{

int i_value;

if(mysem_id == -1){/*如果没有创建或者获取到信号灯的句柄,要先获取句柄*/

if((mysem_id=semget(SEM_KEY,SEMSIZE,IPC_CREAT|0666))==-1){

perror("semget err!\n");

exit(-1);

}

}

i_value = semctl(mysem_id,s_id,GETVAL);

if(i_value == -1){

perror("semctl err:");

exit(-1);

}

return i_value;

}

mywait用于对信号等进可回滚的P操作,可回滚的意思是,当对信号灯进行P操作的进程因为某些意外或者有意识的退出(死亡)后,信号等将自动恢复到操作前的状态,例如某个进程因为做了P操作阻塞了,在阻塞过程中被人人为的kill掉,该进程死后,系统讲自动的对该信号量做一次V操作以保持平衡,这样的好处是在进行互斥操作的多进程程序不会因为某个进程只做P操作而未做V操作就退出后,发生死锁行为。

void mywait(int s_id)

{

struct sembuf    op;

int    i_result;

op.sem_num    =    s_id;

op.sem_op    =    -1;

op.sem_flg    =    SEM_UNDO;

if(mysem_id == -1)

init_mysem(0);

while((i_result = semop(mysem_id,&op,1)) == -1 && errno == EINTR) usleep(5000);

if(i_result==-1){

printf("mywait sid = %d errno = %d   %s\n",s_id,errno,strerror(errno));

if(errno == ERANGE){

printf("semval = %d\n",getmysemvalue(s_id));

}

perror("semop err!\n");

exit(-1);

}

}

mysignal对信号灯进行可回滚的V操作,回滚的好处和刚才的mywait一样

void mysignal(int s_id)

{

struct sembuf    op;

int i_result;

op.sem_num    =    s_id;

op.sem_op    =    1;

op.sem_flg    =    SEM_UNDO;

if(mysem_id == -1)

init_mysem(0);

while((i_result = semop(mysem_id,&op,1)) == -1 && errno == EINTR) usleep(5000);

if(i_result==-1){

printf("mysignal s_id = %d  errno = %d   %s\n",s_id,errno,strerror(errno));

if(errno == ERANGE){

printf("semval = %d\n",getmysemvalue(s_id));

}

perror("semop err!\n");

exit(-1);

}

}

myuwait 是对信号灯进行不可回滚的P操作,使用起来要各位小心。否则容易发生死锁

void myuwait(int s_id)

{

struct sembuf    op;

int i_result;

op.sem_num    =    s_id;

op.sem_op    =    -1;

op.sem_flg    =    0;

if(mysem_id == -1)

init_mysem(0);

while((i_result = semop(mysem_id,&op,1)) == -1 && errno == EINTR) usleep(5000);

if(i_result==-1){

printf("myuwait s_id = %d  errno = %d   %s\n",s_id,errno,strerror(errno));

if(errno == ERANGE){

printf("semval = %d\n",getmysemvalue(s_id));

}

perror("semop err!\n");

exit(-1);

}

}

myusignal是对信号灯进行不可回滚的V操作

void myusignal(int s_id)

{

struct sembuf    op;

int i_result;

op.sem_num    =    s_id;

op.sem_op    =    1;

op.sem_flg    =    0;

if(mysem_id == -1)

init_mysem(0);

while((i_result = semop(mysem_id,&op,1)) == -1 && errno == EINTR) usleep(5000);

if(i_result==-1){

printf("myusignal s_id = %d  errno = %d   %s\n",s_id,errno,strerror(errno));

if(errno == ERANGE){

printf("semval = %d\n",getmysemvalue(s_id));

}

perror("semop err!\n");

exit(-1);

}

}

需要注意的是多某个信号灯变量做可回滚的P操作,就必须使用可回滚的V操作,就是说如果对某个信号灯用mywait操作,就必须使用mysignal做V操作,而不能使用myusignal,并且其他地方要对该信号灯变量做P,V操作,都必须使用mywait  和  mysignal ,mywait  和 myuwait不能对同一个信号等变量混合使用,否则系统会发生不可预测的错误,我的经验是,混合使用到一定时间后,信号等变量的值会突然成一个很大的随机数。

代码范例可到 下载

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值