清单 5. 使用信号量来保护关键部分
#include
#include
#include
#include/* For strerror(3c) */
#include
#include
#include
int main (int argc, char **argv) {
key_t ipckey;
int semid;
struct sembuf sem[2]; /* sembuf defined in sys/sem.h */
/* Generate the ipc key */
ipckey = ftok("/tmp/foo", 42);
/* Set up the semaphore set. 4 == READ, 2 == ALTER */
semid = semget(ipckey, 1, 0666 | IPC_CREAT);
if (semid < 0) {
printf("Error - %sn", strerror(errno));
_exit(1);
}
/* These never change so leave them outside the loop */
sem[0].sem_num = 0;
sem[1].sem_num = 0;
sem[0].sem_flg = SEM_UNDO; /* Release semaphore on exit */
sem[1].sem_flg = SEM_UNDO; /* Release semaphore on exit */
while(1) { /* loop forever */
printf("[%s] Waiting for the semaphore to be releasedn", argv[1]);
/* Set up two semaphore operations */
sem[0].sem_op = 0; /* Wait for zero */
sem[1].sem_op = 1; /* Add 1 to lock it*/
semop(semid, sem, 2);
printf("[%s] I have the semaphoren", argv[1]);
sleep(rand() % 3); /* Critical section, sleep for 0-2 seconds */
sem[0].sem_op = -1; /* Decrement to unlock */
semop(semid, sem, 1);
printf("[%s] Released semaphoren", argv[1]);
sleep(rand() % 3); /* Sleep 0-2 seconds */
}
}
清单 5 的开头与消息队列示例的开头相同 。其中 msgget 在第二个参数中指定消息队列的大小,semget 指定信号量集(Semaphore Set) 的大小 。信号量集是一组共享一个公共 IPC 实例的信号量 。该集合中的信号量数量无法更改 。如果已经创建了信号量集,则 semget 的第二个参数实际上被忽略 。如果 semget 返回一个指示失败的负整数,则打印原因,并退出程序 。
在主 while 循环之前,对 sem_num 和 sem_flg 进行了初始化,因为它们在整个示例中保持一致 。此外还指定了 SEM_UNDO,以便在信号量拥有者未能释放该信号量就已退出的情况下,不会锁定所有其他应用程序 。
该循环中还打印了一个状态消息,以指示应用程序已开始等待信号量 。此输出附带第一个命令行参数作为前缀,以将它与其他实例区分开来 。在进入关键部分之前,应用程序锁定了信号量 。此示例中指定了两个信号量指令 。第一个为 0,意味着应用程序将等待,直至信号量值恢复为 0 。第二个为 1,意味着在信号量恢复为零之后,将向该信号量加 1 。应用程序调用 semop 以运行指令,并向其传递信号量 ID、数据结构的地址和要使用的 sembuf 指令数量 。
在 semop 返回以后,应用程序知道它已经锁定了信号量,并打印一个消息以指示这一点 。然后关键部分将会运行,在此例中是随机地暂停几秒 。最后,使用 semop 值 -1 来运行单个 sembuf 命令,从而释放信号量,这实际上是从信号量减去 1,并将其值恢复为 0 。随后打印更多的调试输出,应用程序随机暂停,然后继续执行 。清单 6 显示了此应用程序的两个实例的输出 。
清单 6. 两个使用信号量来保护关键部分的程序
sunbox$ ./sem_example a & ./sem_example b &
[a] Waiting for the semaphore to be released
[a] I have the semaphore
[b] Waiting for the semaphore to be released
[a] Released semaphore
[b] I have the semaphore
[a] Waiting for the semaphore to be released
[b] Released semaphore
[a] I have the semaphore
[a] Released semaphore
[a] Waiting for the semaphore to be released
[a] I have the semaphore
清单 6 显示了运行的示例的两个实例,这两个实例分别具有名称 a 和 b 。首先,a 获得信号量,在 a 拥有该信号量的同时,b 尝试获得一个锁 。一旦释放了信号量,b 即获得锁 。现在情况颠倒过来,变为等待 b 完成 。最后,a 在信号量被释放后再次获得该信号量,因为 b 没有等待 。
推荐阅读
- X648使用中的两点不尽完美之处
- 利用 UNIX 脚本来管理 DS4000 磁盘阵列系统
- 微信中使用传图识字详细操作方法
- 对话 UNIX,第 13 部分: 另外十种命令行组合
- UNIX 生产力技巧
- UNIX 新手指南,第 1 部分: 文件维护工具
- N1100使用10天有感
- iphone11gps在哪
- 使用 UNIX find 命令的高级技术
- 对话 UNIX: 更多 shell 脚本技术
