注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

多多的爹

 
 
 

日志

 
 

读程序,学习Linux编程(四十三)  

2010-09-07 20:57:27|  分类: 默认分类 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

4.11. 信号量

多进程对共享数据对象读取,容易发生竞争,此时要用到信号量,它是一个计数器。大概原因是为了原子操作,Linux设计成可以对多个信号量同时操作。以下是相关函数:

#include

#include

#include

int semget(key_t key, int nsems, int semflg); // 创建信号量集,注意是创建了nsems个信号量

int semctl(int semid, int semnum, int cmd, ...); // 初始化信号量,修改属性,删除信号量

int semop(int semid, struct sembuf *sops, unsigned nsops); // 增加或者减少信号

int semtimedop(int semid, struct sembuf *sops, unsigned nsops, struct timespec *timeout); // 同semop,多增加了超时的功能。

同样是主次进程使用,先说主进程:

1. 用semget创建一个信号量集。key是一个提前约定的数值,同样不要用IPC_PRIVATE。nsems 指定有几个信号量,因此,至少是一个大于0的整数。semflg设定成IPC_CREAT | IPC_EXCL | 0660。0660前面在讲文件权限的时候提到过,不多说了。创建失败返回-1。

2. 用semctl设置为每一个信号量初始值,semnum是信号量序号,cmd设置为SETVAL,第四个参数表示每个信号量允许同时访问几次。

3. 用semop测试信号量。struct sembuf的定义如下:

/* semop system calls takes an array of these. */

struct sembuf {

unsigned short sem_num; /* semaphore index in array */

short sem_op; /* semaphore operation */

short sem_flg; /* operation flags */

};

一般将sem_op设置成-1,sem_flg设置为0。如果不想等待,可以设置成IPC_NOWAIT。

semop的第二个参数可以是一个sembuf的数组,nsops表示数组长度。

4. 信号量=0,表示没有资源可用,进程进入睡眠等待信号量大于0。

5. 信号量>0,进程被唤醒后,并加上sem_op。

6. 访问资源。

7. 访问完后,再用semop为信号量+1。

8. 不需要信号量,用semctl删除,cmd设置成IPC_RMID。

次进程流程。次进程用semget打开信号量集,semflg设置成0660。访问资源的过程与主进程相同。只是最后不需要删除信号量,因为有主进程来完成了。

有一套sem_XXX的信号量函数,这套函数只能在单个进程内同步,虽然用起来简单,但完全可以用semget系列代替,这里就不提倡用了。

下面是我写的测试代码:

// 主进程程序testsem1.c

#include

#include

#include

#include

#include

#include

main()

{

key_t key = 1987;

int semid = semget(key, 2, IPC_CREAT | IPC_EXCL | 0660);

if (semid == -1)

{

perror("failed to create a set of semaphore");

if (errno == EEXIST)

{

semid = semget(key, 2, 0660);

if (semid != -1)

{

semctl(semid, 0, IPC_RMID);

semctl(semid, 1, IPC_RMID);

}

}

exit(1);

}

printf("create a set of semaphore %d\n", semid);

if (-1 == semctl(semid, 0, SETVAL, 1))

{

perror("failed to set the number for semaphore 0");

goto BYE;

}

if (-1 == semctl(semid, 1, SETVAL, 1))

{

perror("failed to set the number for semaphore 1");

goto BYE;

}

struct sembuf sops;

sops.sem_num = 0;

sops.sem_op = -1;

sops.sem_flg = 0;//IPC_NOWAIT;

SEM_UNDO

if (-1 == semop(semid, &sops, 1))

{

perror("failed to get the resource");

goto BYE;

}

printf("Now I get the resource.\n");

int i;

for (i = 0; i <5 iu>

{

sleep(1);

write(1, ".", 1);

}

printf("\nNow I release the resource.\n");

sops.sem_num = 0;

sops.sem_op = 1;

sops.sem_flg = 0;

if (-1 == semop(semid, &sops, 1))

{

perror("failed to get the resource");

goto BYE;

}

sleep(3);

BYE:

semctl(semid, 0, IPC_RMID);

semctl(semid, 1, IPC_RMID);

}

// 次进程程序testsem2.c

#include

#include

#include

#include

#include

main()

{

key_t key = 1987;

int semid = semget(key, 2, 0660);

if (semid == -1)

{

perror("failed to open a set of semaphore");

exit(1);

}

printf("open a set of semaphore %d\n", semid);

printf("The first semaphore has %d\n", semctl(semid, 0, GETVAL, 0));

printf("The second semaphore has %d\n", semctl(semid, 1, GETVAL, 0));

{

struct sembuf sops;

sops.sem_num = 1;

sops.sem_op = -1;

sops.sem_flg = 0;//IPC_NOWAIT;

if (-1 == semop(semid, &sops, 1))

{

perror("failed to get the resource1");

exit(1);

}

printf("Now I get the resource1.\n");

int i;

for (i = 0; i <1 iu>

{

sleep(1);

write(1, ".", 1);

}

printf("\nNow I release the resource1.\n");

sops.sem_num = 1;

sops.sem_op = 1;

sops.sem_flg = 0;

if (-1 == semop(semid, &sops, 1))

{

perror("failed to get the resource1");

exit(1);

}

}

{

struct sembuf sops;

sops.sem_num = 0;

sops.sem_op = -1;

sops.sem_flg = 0;//IPC_NOWAIT;

if (-1 == semop(semid, &sops, 1))

{

perror("failed to get the resource2");

exit(1);

}

printf("Now I get the resource2.\n");

int i;

for (i = 0; i <1 iu>

{

sleep(1);

write(1, ".", 1);

}

printf("\nNow I release the resource2.\n");

sops.sem_num = 0;

sops.sem_op = 1;

sops.sem_flg = 0;

if (-1 == semop(semid, &sops, 1))

{

perror("failed to get the resource");

}

}

}

编译后,打开两个终端窗口,在第一个终端商品运行./testsem1,然后马上切换到另一个终端窗口运行./testsem2,看看情况如何。

  评论这张
 
阅读(7)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017