使用 System V Semaphores API 实现 POSIX Semaphore API

使用 System V Semaphore API 将 semaphore 支持从标准 POSIX API 平台向外扩展

您需要使用 POSIX API 但开发平台却不支持它们(比如 z/OS)?不要因此望而却步。我们将了解如何使用 System V Semaphores API 实现 POSIX Semaphore API,从而将您的代码带到更多平台并保持它的可维护性。

Suchitra Venugopal, 高级系统分析师, IBM

Suchitra Venugopal 的照片Suchitra Venugopal 在软件行业有 10 年的从业经验,主要致力于开源系统技术。她还从事过从 IBM Optim 到 HP Itanium 平台以及从 SPSS 到 zOS 平台的迁移工作。目前,她效力于 Platform Technology Centre。她是 Dev works 上有关调试格式(DWARF 和 STAB)的一篇文章 (http://www.ibm.com/developerworks/cn/opensource/os-debugging/index.html) 的合著者之一。



Shikha Maheshwari, 系统软件工程师, IBM

Shikha Maheshwari 的照片Shikha Maheshwari 于 2006 年加入 IBM India Software Labs,自此之后一直是 Platform Technology Centre 团队的一名成员。她曾从事过 IBM 产品以及几个平台上的多个迁移、测试和开发项目。她研究过的产品包括 TxSeries、TSIEM、TEM、ISW、SPSS、Cognos 和 WBM。



Adarsh Thampan, 开发经理, IBM

Adarsh Thampan 的照片Adarsh Thampan 所从事的工作包括将在 C/C++ 技术上构建的 IBM 产品迁移到 HP Itanium、System Z 和 z/OS 上的 Linux。他还参与合著了白皮书 “Mixed Platform Stack Project: Linux on System z and IBM z/OS (http://www-03.ibm.com/support/techdocs/atsmastr.nsf/WebIndex/WP101522)”。他还是 Dev works 上有关调试格式(DWARF 和 STAB)的一篇文章 (http://www.ibm.com/developerworks/cn/opensource/os-debugging/index.html) 的合著者之一。



2012 年 11 月 29 日

概述

在将代码移植到 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 Semaphore

Semaphore 可以有两种类型: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/OS
POSIXYYYYYYN
System 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(参见 清单 1)。semget() 函数和 semctl() 函数内返回的错误代码与 POSIX 实现内的代码相同。

清单 1. sem_init 函数实现
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)

清单 2 显示了如何使用 semctl() 函数实现 sem_destroy

清单 2. sem_destroy 函数实现
int ret = semctl(*semid,0,IPC_RMID);

要删除指定的 semaphore 集,请使用 IPC_RMID。

int sem_wait(int *semid)

该函数在 semaphore 上放置了一个锁。清单 3 显示了如何使用 semop() 完成此操作。

清单 3. sem_wait 函数实现
        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

清单 4. sem_trywait 函数实现
        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

清单 5. sem_post 函数实现
        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 实现在其他平台内的错误代码。


测试应用程序

123 中的流程图显示了用来测试 semaphore API 的一个简单的测试应用程序。(图 1、2 和 3 形成了一个单一的流程图,但为了格式化目的进行了分段显示。查看 图 1、2 和 3 的的放大图。)这个测试应用程序是使用 System V semaphore 实现的。此测试应用程序创建了一个线程数组并使用了很多 semaphore POSIX API,比如 sem_init()sem_post()sem_destroy()sem_wait()sem_trywait() 等。

图 1. 测试应用程序的流程图,第 1 部分
测试应用程序的流程图,第 1 部分
图 2. 测试应用程序的流程图,第 2 部分
测试应用程序的流程图,第 2 部分
图 3. 测试应用程序的流程图,第 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 运行得很好。

清单 6 显示了通过利用 System V semaphore API 的 POSIX 实现所实现的测试应用程序的输出:

清单 6. 使用了 System V semaphore API 的测试应用程序的输出
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#

清单 7 显示了使用已经存在的 POSIX API 实现的测试应用程序的输出:

清单 7. 使用了现有 POSIX API 的测试应用程序的输出
bash-3.2# ./test1original

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 no 4 id = 1286 created
Thread id 1029 is in ThreadFunction1, semaphore is already locked and not waiting. 
Hence will not increment the counter
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#

这两个应用程序在 AIX 内有相同的输出。

案例 2 - 利用通过 System V 实现的 semaphore APIs 在 z/OS 上测试应用程序

我们用相同的测试应用程序在 z/OS 内进行构建并测试了使用 System V semaphore 实现的 semaphore 文件。而在 AIX 上,我们还运行了另一个使用了已经可用的 POSIX APIS 的测试应用程序,并对输出进行了比较。

如果 z/OS 上的测试结果和 AIX 上的测试结果相同,那么您就可以放心地得出结论:利用了 System V semaphore API 的 POSIX semaphore 实现运行得很好。

清单 8 显示了相同的测试应用程序(比如在 AIX 内)在 z/OS 内的输出:

清单 8. 使用了 SYTEM V semaphore API 的测试应用程序输出
STLAB60:../finalCode:> ./test1sys5

Thread no 0 id = 542160384 created
Threadid  id =542160384(ThreadFunction1), locked and incrementing the count
Thread no 1 id = 542195200 created      Count (ThreadFunction1) = 1
Thread no 2 id = 542199552 created
Thread no 3 id = 542203904 created
Thread no 4 id = 542208256 created
Thread no 5 id = 542212608 created
Thread no 6 id = 542216960 created
Thread no 7 id = 542221312 created
Thread no 8 id = 542225664 created
Thread no 9 id = 542230016 created
Thread id 542216960 is in ThreadFunction1, semaphore is already locked and not waiting. 
Hence will not increment the counter
Thread id 542230016 is in ThreadFunction1, semaphore is already locked and not waiting. 
Hence will not increment the counter
Thread id 542203904 is in ThreadFunction1, semaphore is already locked and not waiting. 
Hence will not increment the counter
Thread 542160384 going to release lock
Thread id = 542195200(ThreadFunction2) , locked and incrementing the count     
Count (ThreadFunction2) = 2
Thread id 542195200 going to release lock
Thread id = 542199552(ThreadFunction2) , locked and incrementing the count     
Count (ThreadFunction2) = 3
Thread id 542199552 going to release lock
Thread id = 542221312(ThreadFunction2) , locked and incrementing the count     
Count (ThreadFunction2) = 4
Thread id 542221312 going to release lock
Thread id = 542225664(ThreadFunction2) , locked and incrementing the count     
Count (ThreadFunction2) = 5
Thread id 542225664 going to release lock
Thread id = 542208256(ThreadFunction2) , locked and incrementing the count     
Count (ThreadFunction2) = 6
Thread id 542208256 going to release lock
Thread id = 542212608(ThreadFunction2) , locked and incrementing the count     
Count (ThreadFunction2) = 7
Thread id 542212608 going to release lock
All threads joined, Final count = 7

清单 9 显示了使用了已经可用的 POSIX API 的测试应用程序在 AIX 上的输出:

清单 9. 使用了已经可用的 POSIX API 的测试应用程序输出
bash-3.2# ./test1original

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 no 4 id = 1286 created
Thread id 1029 is in ThreadFunction1, semaphore is already locked and not waiting. 
Hence will not increment the counter
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#

从结果可以看出,测试应用程序在 z/OS 和 AIX 上具有相同的行为。


结束语

要在任何一个遗留平台(比如 z/OS)上使用 POSIX semaphore API,可以 下载 semaphore.h 和 semaphore.c 文件,并使用它们来调用任何的 POSIX API。我们成功地测试了这一代码段并证实了它的正确性。


下载

描述名字大小
Semaphore 测试应用程序semaphore_testapplns.zip16KB

参考资料

学习

获得产品和技术

  • 获取 IBM 试用软件(可以通过下载 获得):使用专门面向开发人员的软件改进您的下一个开源开发项目。

讨论

条评论

developerWorks: 登录

标有星(*)号的字段是必填字段。


需要一个 IBM ID?
忘记 IBM ID?


忘记密码?
更改您的密码

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件

 


在您首次登录 developerWorks 时,会为您创建一份个人概要。您的个人概要中的信息(您的姓名、国家/地区,以及公司名称)是公开显示的,而且会随着您发布的任何内容一起显示,除非您选择隐藏您的公司名称。您可以随时更新您的 IBM 帐户。

所有提交的信息确保安全。

选择您的昵称



当您初次登录到 developerWorks 时,将会为您创建一份概要信息,您需要指定一个昵称。您的昵称将和您在 developerWorks 发布的内容显示在一起。

昵称长度在 3 至 31 个字符之间。 您的昵称在 developerWorks 社区中必须是唯一的,并且出于隐私保护的原因,不能是您的电子邮件地址。

标有星(*)号的字段是必填字段。

(昵称长度在 3 至 31 个字符之间)

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件.

 


所有提交的信息确保安全。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=Linux, Open source, Java technology
ArticleID=847950
ArticleTitle=使用 System V Semaphores API 实现 POSIX Semaphore API
publish-date=11292012