当前位置:嗨网首页>书籍在线阅读

04-同步工具

  
选择背景色: 黄橙 洋红 淡粉 水蓝 草绿 白色 选择字体: 宋体 黑体 微软雅黑 楷体 选择字体大小: 恢复默认

43.3 同步工具

通过图43-1中的同步工具可以协调进程的操作。通过同步可以防止进程执行诸如同时更新一块共享内存或同时更新文件的同一个数据块之类的操作。如果没有同步,那么这种同时更新的操作可能会导致应用程序产生错误的结果。

UNIX系统提供了下列同步工具。

  • 信号量:一个信号量是一个由内核维护的整数,其值永远不会小于0。一个进程可以增加或减小一个信号量的值。如果一个进程试图将信号量的值减小到小于0,那么内核会阻塞该操作直至信号量的值增长到允许执行该操作的程度。(或者进程可以要求执行一个非阻塞操作,那么就不会发生阻塞,内核会让该操作立即返回并返回一个标示无法立即执行该操作的错误。)信号量的含义是由应用程序来确定的。一个进程减小一个信号量(如从1到0)是为了预约对某些共享资源的独占访问,在完成了资源的使用之后可以增加信号量来释放共享资源以供其他进程使用。最常用的信号量是二元信号量——一个值只能是0或1的信号量,但处理一类共享资源拥有多个实例的应用程序需要使用最大值等于共享资源数量的信号量。Linux既提供了System V信号量,又提供了POSIX信号量,它们的功能是类似的。
  • 文件锁:文件锁是设计用来协调操作同一文件的多个进程的动作的一种同步方法。它也可以用来协调对其他共享资源的访问。文件锁分为两类:读(共享)锁和写(互斥)锁。任意进程都可以持有同一文件(或一个文件的某段区域)的读锁,但当一个进程持有了一个文件(或文件区域)的写锁之后,其他进程将无法获取该文件(或文件区域)上的读锁和写锁。Linux通过flock()和fcntl()系统调用来提供文件加锁工具。flock()系统调用提供了一种简单的加锁机制,允许进程将一个共享或互斥锁加到整个文件上。由于功能有限,现在已经很少使用flock()这个加锁工具了。fcntl()系统调用提供了记录加锁,允许进程在同一文件的不同区域上加上多个读锁和写锁。
  • 互斥体和条件变量:这些同步工具通常用于POSIX线程,第30章对此进行了介绍。

一些UNIX实现,包括安装了能提供NPTL线程实现的glibc的Linux系统,允许在进程间共享互斥体和条件变量。SUSv3允许但并不要求实现支持进程间共享的互斥体和条件变量。所有UNIX系统都没有提供这个功能,因此很少使用它们来进行进程同步。

在执行进程间同步时通常需要根据功能需求来选择工具。当协调对文件的访问时文件记录加锁通常是最佳的选择,而对于协调对其他共享资源的访问来讲,信号量通常是更佳的选择。

通信工具也可以用来进行同步。如在44.3节中使用了一个管道来同步父进程与子进程的动作。一般来讲,所有数据传输工具都可以用来同步,只是同步操作是通过在工具中交换消息来完成的。

自内核2.6.22起,Linux通过eventfd()系统调用额外提供了一种非标准的同步机制。这个系统调用创建了一个eventfd对象,该对象拥有一个相关的由内核维护的8字节无符号整数,它返回一个指向该对象的文件描述符。向这个文件描述符中写入一个整数将会把该整数加到对象值上。当对象值为0时对该文件描述符的read()操作将会被阻塞。如果对象的值非零,那么read()会返回该值并将对象值重置为0。此外,可以使用poll()、select()以及epoll来测试对象值是否为非零,如果是非零的话就表示文件描述符可读。使用eventfd对象进行同步的应用程序必须要首先使用eventfd()创建该对象,然后调用fork()创建继承指向该对象的文件描述符的相关进程。更多细节信息可参考eventfd(2)手册。