apue上面p325对文件对象的互斥锁进行了说明,但是本屌丝不是很明白,在网上查阅了很多的资料和Linux下的man之后,现在总结如下:
首先需要明确是每个文件对象都有与之相关联的锁,来实现对文件对象访问的同步操作,使之序列化,我这里将这句话理解为每个文件对象在打开的时候或者是新建的时候都与之关联了一把锁,这个貌似和共享变量的情况不同,共享变量需要我们自己提供锁,而这里以及提供好了。而且这把锁是递归锁,原因很简单啊,在多线程当中,若是在同一个线程中调用标准I/O函数,若这个锁不是递归锁,则会出现死锁的现象
标准I/O函数都是线程安全的函数,所谓线程安全的函数在对于全局变量的访问的时候,一定要提供同步操作.既然标准I/O是线程安全的,那么它是怎样实现的呢?原来是通过上面说的位每个文件对象赋予一个锁定计数和 (当锁定计数非零时) 一个所有者线程来实现的。对每个库函数调用,这些函数等待直到文件对象 FILE 不再被一个不同的线程锁定,然后锁定它,进行所需的 I/O 操作,再次对它解锁。
既然这两个函数对于使用者来说是透明不可见的,那么介绍它们有什么用呢?apue上面提供了两个理由,需要进行更加细节的控制。其一,也许某个线程需要进行不可分割的一系列 I/O 操作,不应当被其他线程的 I/O 所中断(操作原子化)。其二,出于效率因素,应当避免进行过多的锁定来提高效率(效率问题,采用非锁定版本)
为此,一个线程可以显式地锁定文件对象 FILE,接着进行它的一系列 I/O 操作,然后解锁。这样可以避免其他线程干扰。如果这样做的原因是需要达到更高的效率,应当使用 stdio 函数的非锁定版本来进行 I/O 操作:使用 getc_unlocked() 和 putc_unlocked() 来代替 getc() 和 putc()。因为这个时候若是不采用非锁定版本的话,不是不行,只是效率会很低,因为这个时候在不同的加锁和解锁。
函数 flockfile() 等待 *filehandle 不再被其他的线程锁定,然后使当前线程成为 *filehandle 的所有者,然后增加锁定计数 lockcount。
函数 funlockfile() 减少锁定计数。
函数 ftrylockfile() 是 flockfile() 的非锁定版本。它在其他线程拥有 *filehandle时不做任何处理,否则取得所有权并增加锁定计数。
RETURN VALUE 返回值
函数 ftrylockfile() 返回零,如果成功的话 (获得了锁定);如果失败就返回非零。