使用 System V Semaphores API 实现 POSIX Semaphore API-1
- UID
- 1066743
|
使用 System V Semaphores API 实现 POSIX Semaphore API-1
概述在将代码移植到 z/OS 平台时,您会面临的一个重要挑战是 POSIX semaphore API 在 z/OS 上的可用性。通常,在 Linux®/UNIX™/Windows® 平台上运行的很多程序都是用 POSIX semaphore 开发的。
这个问题的一个解决方案是使用 System V API 代替 POSIX API 来实现 z/OS。这会涉及到整个代码中大量的代码更改,以及大量的编写和测试工作。另一个更好的解决方案是使用可用的 System V API 在 z/OS 中实现 POSIX API。如果采用这种方法,移植所需的代码更改会很少。这些代码更改不包含在应用程序代码中,而是作为单独的 semaphore 标头和 C 文件包含在内。此标头和 C 文件是通用的,可用于任何平台。
本文阐释了如何使用 System V Semaphore API 来实现 POSIX Semaphore API。
本文对于想要使用 POSIX API 但开发平台只支持 System V API(比如 z/OS)的开发人员会非常有帮助。而且本文还会从开发角度对 POSIX 和 System V semaphore 进行显著的区分。
对比 POSIX Semaphore 和 System V SemaphoreSemaphore 可以有两种类型:POSIX Semaphore 或 System V semaphore。
您可以在 semaphores 上以单独的单元或以集合中的元素进行操作。由于 System V IPC semaphores 可以位于一个巨大的数组中,所以它们是属于极其重量级的。Semaphore 集合由一个控制结构和一个 semaphore 数组组成。一组 semaphore 可以包括最多 25 个元素。System V IPC semaphore 函数包括 semget()、semop() 和 semctl()。
- semget() - 创建一个新的 semaphore 集或使用 semget() 系统调用访问一个现有集合。
- semop() - 执行 semaphore 操作。
- semctl() - 如果您是该 semaphore 的创作者,那么可以更改它的所有权或许可权限。
POSIX semaphore 要比 System V semaphore 轻很多。POSIX semaphore 结构定义了一个单一的 semaphore,而不是一个 semaphore 数组。POSIX semaphore 函数包括:
- sem_open() - 连接到(也可以根据情况创建)一个命名的 semaphore
- sem_init() - 初始化一个 semaphore 结构(属于调用程序内部的结构,所以不是一个命名的 semaphore)
- sem_close() - 终止一个打开的 semaphore 的连接
- sem_unlink() - 终止一个打开的 semaphore 的连接并在最后的进程关闭该连接时删除此 semaphore
- sem_destroy() - 初始化一个 semaphore 结构(属于调用程序内部的结构,所以不是一个命名的 semaphore)
- sem_getvalue() - 将 semaphore 的值复制到指定的整数
- sem_wait() 和 sem_trywait() - 当 semaphore 由其他进程持有时会发生阻塞,或是如果 semaphore 由另一个进程持有,则返回一个错误
- sem_post() - 增加 semaphore 的数目
POSIX 自带了创建、初始化和在 semaphore 上执行操作所对应的简单语义。这些语义提供了一种处理进程间通信的有效方式。如果您需要在单个步骤内执行多次增量-减量来实现原子操作,那么 System V semaphore 会非常有用。除此之外,请尽量使用 POSIX semaphore。
Semaphore 在 z/OS 上的限制z/OS 只支持 System V Semaphore,不支持 POSIX semaphore。
在 z/OS 上没有可用的 POSIX API。z/OS 只有三个面向 semaphore 的 System V API,分别为 semop()、semget() 和 semctl()。如果想要在 z/OS 内使用 semaphore API,那么只能使用 System V API。
表 1. 不同平台上的 Semaphore 支持
LinuxAIX®zLinuxHPSolarisMac OSz/OSPOSIXYYYYYYNSystem VYYYYYYY
使用 System V Semaphore API 实现 POSIX Semaphore API所有 POSIX semaphore 函数和类型都是在 semaphore.h 内原型化或定义的。在某些遗留平台(比如 z/OS)上,只有 System V semaphore 函数可用。因此,semaphore.h(用以定义 POSIX Semaphore 函数)在 z/OS 上是不可用的。System V semaphore 函数在 sys/sem.h 内原型化。
本节将展示一种使用 System V Semaphore API 实现 POSIX semaphore API 的方式。这种方式是使用 POSIX semaphore 在 z/OS 和 AIX 中实现的而且测试效果不错。
两个独立的文件 Semaphore_zOS.h 和 Semaphore_zOS.c 使用 POSIX API 在 z/OS 内实现了 System V semaphore API。我们实现的函数包括:
int sem_init(int *semid,int pshared,unsigned int value)此函数的实现使用了 System V semaphore 的 semget 和 semctl API(参见 )。semget() 函数和 semctl() 函数内返回的错误代码与 POSIX 实现内的代码相同。
清单 1. sem_init 函数实现1
2
3
4
5
6
7
8
9
10
11
12
| int sem_init(int *sem,int pshared,unsigned int value)
{
// get the semaphore first
semid = semget(key, nsems, IPC_CREAT | IPC_EXCL | 0666);
if(semid== -1)
/*assign err code and return*/
else
int ret = semctl(*semid,0,SETVAL,value); // initialize the semaphore
if(ret == -1)
/* assign errcode for semctl and return */
return ret;
}
|
int sem_destroy(int *semid) 显示了如何使用 semctl() 函数实现 sem_destroy:
清单 2. sem_destroy 函数实现1
| int ret = semctl(*semid,0,IPC_RMID);
|
要删除指定的 semaphore 集,请使用 IPC_RMID。
int sem_wait(int *semid)该函数在 semaphore 上放置了一个锁。 显示了如何使用 semop() 完成此操作。
清单 3. sem_wait 函数实现 1
2
3
4
| sb.sem_num=0;
sb.sem_op=-1; //Allocate resources
sb.sem_flg=0;
if (semop(*semid, sb, 1) == -1)
|
int sem_trywait(int *semid)此函数还在 semaphore 上放置了一个锁,并使用 semop() 得以实现。除了 sem_flg=IPC_NOWAIT 外,该实现与 sem_wait 类似。参见 。
清单 4. sem_trywait 函数实现1
2
3
4
| sb.sem_num=0;
sb.sem_op=-1; //Allocate resources
sb.sem_flg= IPC_NOWAIT;
if (semop(*semid, sb, 1) == -1)
|
如果 semaphore 目前可以锁定,那么此函数会只锁定这个 semaphore。sem_wait 函数会一直等待直到该 semaphore 上有锁定,而 sem_trywait 则不会等待。sem_trywait 只检查锁定目前是否可用,否则就返回该锁定。
int sem_post(int *semid)此函数使用 semop() 释放 semaphore 上的锁定。参见 。
清单 5. sem_post 函数实现1
2
3
4
| sb.sem_num=0;
sb.sem_op=1; // Release resources.
sb.sem_flg=0;
if (semop(*semid, sb, 1) == -1)
|
像 sem_open()、sem_close()、sem_unlink() 和 sem_getvalue() 这样的 POSIX API 则没有被实现,因为不需要。您也可以用同样的方式实现它们!
要为这些实现设置错误代码,可以参照 POSIX 实现在其他平台内的错误代码。
测试应用程序图 、 和 中的流程图显示了用来测试 semaphore API 的一个简单的测试应用程序。(图 1、2 和 3 形成了一个单一的流程图,但为了格式化目的进行了分段显示。查看 。)这个测试应用程序是使用 System V semaphore 实现的。此测试应用程序创建了一个线程数组并使用了很多 semaphore POSIX API,比如 sem_init()、sem_post()、sem_destroy()、sem_wait()、sem_trywait() 等。
图 1. 测试应用程序的流程图,第 1 部分图 2. 测试应用程序的流程图,第 2 部分图 3. 测试应用程序的流程图,第 3 部分案例 1 - 使用 POSIX semaphore API 在 AIX 上进行测试并使用 System V 实现 semaphore API本节显示了 AIX 平台上测试应用程序的结果,一个测试应用程序使用的是已经可用的 POSIX semaphore API,另一个测试应用程序使用的是用 System V API 实现的 POSIX API。获得 semaphore 的线程顺序因平台和优先级的不同而不同。
如果来自这两个测试应用程序的结果完全相同,那么可以放心地得出结论:用 System V API 实现的 POSIX API 运行得很好。
显示了通过利用 System V semaphore API 的 POSIX 实现所实现的测试应用程序的输出:
清单 6. 使用了 System V semaphore API 的测试应用程序的输出1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
| bash-3.2# ./test1posiximpln
Thread no 0 id = 258 created
Threadid id =258(ThreadFunction1), locked and incrementing the count
Count (ThreadFunction1) = 1
Thread no 1 id = 515 created
Thread no 2 id = 772 created
Thread no 3 id = 1029 created
Thread id 1029 is in ThreadFunction1, semaphore is already locked and not waiting.
Hence will not increment the counter
Thread no 4 id = 1286 created
Thread no 5 id = 1543 created
Thread no 6 id = 1800 created
Thread id 1800 is in ThreadFunction1, semaphore is already locked and not waiting.
Hence will not increment the counter
Thread no 7 id = 2057 created
Thread no 8 id = 2314 created
Thread no 9 id = 2571 created
Thread id 2571 is in ThreadFunction1, semaphore is already locked and not waiting.
Hence will not increment the counter
Thread 258 going to release lock
Thread id = 515(ThreadFunction2) , locked and incrementing the count
Count (ThreadFunction2) = 2
Thread id 515 going to release lock
Thread id = 772(ThreadFunction2) , locked and incrementing the count
Count (ThreadFunction2) = 3
Thread id 772 going to release lock
Thread id = 1286(ThreadFunction2) , locked and incrementing the count
Count (ThreadFunction2) = 4
Thread id 1286 going to release lock
Thread id = 1543(ThreadFunction2) , locked and incrementing the count
Count (ThreadFunction2) = 5
Thread id 1543 going to release lock
Thread id = 2057(ThreadFunction2) , locked and incrementing the count
Count (ThreadFunction2) = 6
Thread id 2057 going to release lock
Thread id = 2314(ThreadFunction2) , locked and incrementing the count
Count (ThreadFunction2) = 7
Thread id 2314 going to release lock
All threads joined, Final count = 7
bash-3.2#
|
显示了使用已经存在的 POSIX API 实现的测试应用程序的输出: |
|
|
|
|
|