最好的参考资料:
1.师从互联网。
2.UNP v2 Posix IPC的相关章节7、8、9。
3.Linux man 命令。
4.APUE 相关章节11、14。
第一条:概述
这里介绍的是Posix.1线程标准的:互斥锁、条件变量、读写锁。他们主要用来同步一个进程内各个线程的,如果把它们放在一个共享内存空间中,Posix允许他们用于进程间同步。如果想了解他们的实现,在libc源码的nptl文件下,你可以找到他们。
我同样也会介绍Posix.1标准的基础:fcntl的记录锁。Linux支持记录锁的所有形式:建议性锁、强制性锁、fcntl、lockf、flock。
顺便说一下,linux内核提供了类型为struct mutex的经典互斥量,以及相关API在linux/mutex.h文件里可以看到。libc未包含他们,有可移植性更好的Posix的原因把。
第二条:互斥锁和条件变量
互斥锁的主要用途:保护临界区(critical region)在任何时候只有一个线程在执行其中的代码。任何时刻只有一个线程可以锁住一个给定的互斥锁。如果这个互斥锁在共享内存区,就可以用来让进程向线程一样的同步(如果这样的话,线程的所有情况都适用进程,下文不再显示指明这点)。实质上,互斥锁的用途就是保护临界区内共享的数据。
互斥锁的初始化:必须在定义互斥锁时初始化。
1.静态分配可以初始化为常值PTHREAD_MUTEX_INITIALIZER(timed)。其值为: { { 0, 0, 0, 0, 0, { 0 } } }。
其他的静态初始化方法:
PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP(recursive,锁多少次就得打开多少次)
PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP(fast,用户自己保证正确性)
PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP(error check,纠错锁,线程不能去解另一个线程加上的锁)
NP代表 non-portable 不可移植!!
2.动态分配和分配在共享内存区中,运行时调用pthread_mutex_init函数初始化他。别忘记用pthread_mutex_destroy函数释放他。
互斥锁是协作性(cooperative)锁:通俗点说就是,每个线程都得遵守对于临界区的代码必须在获得互斥锁的前提下才可以执行的神圣约定。否则互斥锁,就只是浪费了资源的无用代码。
多个线程等在同一个互斥锁的状况:UNPv2上有这样的描述:不同线程可以有不同的优先级,同步函数(互斥锁、读写锁、信号量)将唤醒优先级最高的被阻塞的线程。
编程技巧:可以把共享数据和互斥锁放到一个结构中。
互斥量的类型:Posix .1定义四种类型:
PTHREAD_MUTEX_NORMAL:不做任何错误检测和死锁检测。
1.同一个线程,在前一次lock操作未解锁,再次加锁,第二次加锁的进程将挂起。
2.同一个线程,解锁未上锁的互斥锁,不会报错。
3.一个线程解锁另外一个线程加锁的互斥锁成功!!!!!!!!(多次测试!!!)
//2.6.35内核、nptl线程库、glibc-2.12.2这个结果和这个帖子一致http://blog.youkuaiyun.com/guosha/archive/2008/10/24/3136721.aspx
4.一个线程对互斥锁加锁,另一个线程在对这个互斥锁加锁,另一个线程将会挂起。
5.调度特征是:先等待锁的进程先获得锁。
PTHREAD_MUTEX_RECURSIVE:允许同一线程在互斥量之前对该互斥量进行多次加锁,而且返回错误在出错时,用一个递