读书笔记:第10章 Posix信号量 (1)

《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


你可能感兴趣的:(读书笔记,《UNIX网络编程》)