《UNIX网络编程:卷2》P181-P184:图10-9、10-10、10-11、10-12、10-13
------------------------------------------------------------------
semcreate程序
创建一个有名信号量,允许命令行选项有指定独占创建的-e和指定一个初始值的-i。
/* * semcreate.c * P181 图10-9 创建一个有名信号量 */ #include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include <unistd.h> #include <string.h> #include <errno.h> #include <semaphore.h> #define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) int main(int argc, char *argv[]) { int c, flags; sem_t *sem; unsigned int value; flags = O_RDWR | O_CREAT; value = 1; while ((c = getopt(argc, argv, "ei:")) != -1) { switch (c) { case 'e': flags |= O_EXCL; break; case 'i': // 指定初值 value = atoi(optarg); break; } } if (optind != argc - 1) { fprintf(stderr, "usage: semcreate [-e] [-i initalvalue] <name>\n"); exit(1); } // 创建或打开一个有名信号量 if ((sem = sem_open(argv[optind], flags, FILE_MODE, value)) == SEM_FAILED) { fprintf(stderr, "sem_open error: %s\n", strerror(errno)); exit(1); } // 关闭有名信号量 sem_close(sem); exit(0); }
------------------------------------------------------------------
semunlink程序
删除一个有名信号量的名字。
/* * semunlink.c * P182 图10-10 删除一个有名信号量的名字 */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <semaphore.h> int main(int argc, char *argv[]) { if (argc != 2) { fprintf(stderr, "usage: semunlink <name>\n"); exit(1); } // 删除一个有名信号量 if (sem_unlink(argv[1]) < 0) { fprintf(stderr, "sem_unlink error: %s\n", strerror(errno)); exit(1); } exit(0); }
------------------------------------------------------------------
semgetvalue程序
打开一个有名信号量,取得它的当前值,然后输出该值。
/* * semgetvalue.c * P183 图10-11 取得并输出一个信号量的值 */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <semaphore.h> int main(int argc, char *argv[]) { sem_t *sem; int val; if (argc != 2) { fprintf(stderr, "usage: semgetvalue <name>\n"); exit(1); } // 打开一个有名信号量 if ((sem = sem_open(argv[1], 0)) == SEM_FAILED) { fprintf(stderr, "sem_open error: %s\n", strerror(errno)); exit(1); } // 获取当前信号量的值 if (sem_getvalue(sem, &val) < 0) { fprintf(stderr, "sem_getvalue error: %s\n", strerror(errno)); exit(1); } printf("value = %d\n", val); exit(0); }
------------------------------------------------------------------
semwait程序
打开一个有名信号量,调用sem_wait,取得并输出该信号量的当前值,然后永远阻塞在一个pause调用中。
/* * semwait.c * P183 图10-12 等待一个信号量并输出它的值 */ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <errno.h> #include <semaphore.h> int main(int argc, char *argv[]) { sem_t *sem; int val; if (argc != 2) { fprintf(stderr, "usage: semwait <name>\n"); exit(1); } // 打开一个有名信号量 if ((sem = sem_open(argv[1], 0)) == SEM_FAILED) { fprintf(stderr, "sem_open error: %s\n", strerror(errno)); exit(1); } // 如果该信号量的当前值小于或等于0,该调用就阻塞。结束阻塞后该调用将信号量的值减1 if (sem_wait(sem) < 0) { fprintf(stderr, "sem_wait error: %s\n", strerror(errno)); exit(1); } // 获取当前信号量的值 if (sem_getvalue(sem, &val) < 0) { fprintf(stderr, "sem_getvalue error: %s\n", strerror(errno)); exit(1); } printf("pid %d has semaphore, value = %d\n", getpid(), val); pause(); exit(0); }
------------------------------------------------------------------
sempost程序
挂出一个有名信号量,然后取得并输出该信号量的值。
/* * sempost.c * P184 图10-13 挂出一个信号量 */ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <errno.h> #include <semaphore.h> int main(int argc, char *argv[]) { sem_t *sem; int val; if (argc != 2) { fprintf(stderr, "usage: sempost <name>\n"); exit(1); } // 打开一个有名信号量 if ((sem = sem_open(argv[1], 0)) == SEM_FAILED) { fprintf(stderr, "sem_open error: %s\n", strerror(errno)); exit(1); } // 挂出一个有名信号量 if (sem_post(sem) < 0) { fprintf(stderr, "sem_post error: %s\n", strerror(errno)); exit(1); } // 获取当前信号量的值 if (sem_getvalue(sem, &val) < 0) { fprintf(stderr, "sem_getvalue error: %s\n", strerror(errno)); exit(1); } printf("pid %d has semaphore, value = %d\n", getpid(), val); pause(); exit(0); }
------------------------------------------------------------------
Makefile
semcreate: gcc semcreate.c -o semcreate -lpthread semunlink: gcc semunlink.c -o semunlink -lpthread semgetvalue: gcc semgetvalue.c -o semgetvalue -lpthread semwait: gcc semwait.c -o semwait -lpthread sempost: gcc sempost.c -o sempost -lpthread all: make semcreate semunlink semgetvalue semwait sempost clean: rm semcreate semunlink semgetvalue semwait sempost
------------------------------------------------------------------
编译程序:
$ make all make semcreate semunlink semgetvalue semwait sempost make[1]: 正在进入目录 `/home/user/workspace/unp2/chap10' gcc semcreate.c -o semcreate -lpthread gcc semunlink.c -o semunlink -lpthread gcc semgetvalue.c -o semgetvalue -lpthread gcc semwait.c -o semwait -lpthread gcc sempost.c -o sempost -lpthread make[1]:正在离开目录 `/home/user/workspace/unp2/chap10'
------------------------------------------------------------------
运行程序:
$ ./semcreate /test1 创建一个有名信号量 $ ./semgetvalue /test1 获取信号量的值 value = 1 $ ./semwait /test1 等待信号量 pid 2583 has semaphore, value = 0 ^C [Ctrl+C]终止程序 $ ./semgetvalue /test1 获取信号量的值 value = 0
本例子展示了两个特性:首先,信号量的值是随内核持续的。其次,当我们终止持有信号量锁的semwait时,该信号量的值并不改变。这就是说,当持有某个信号量锁的进程没有释放它就终止时,内核并不给该信号解锁。
接着展示Ubuntu的信号量实现在有进程等待着某个信号量的时候如何处理该信号量的值。
$ ./semgetvalue /test1 value = 0 $ ./semwait /test1 & 后台启动一个semwait程序 [1] 2593 它阻塞,等待信号量 $ ./semgetvalue /test1 获取信号量的值 value = 0 本实现不使用负值 $ ./semwait /test1 & 在后台启动另一个semwait程序 [2] 2595 $ ./semgetvalue /test1 value = 0 值仍然为0,不过有两个进程在等待 $ ./sempost /test1 现在挂出信号 pid 2599 has semaphore, value = 1 pid 2593 has semaphore, value = 0 来自第一个semwait程序的输出 ^C $ ./sempost /test1 pid 2600 has semaphore, value = 1 pid 2595 has semaphore, value = 0 来自第二个semwait程序的输出 ^C