因为同个进程中的各个线程共享整个进程的地址空间,那么就必须在线程之间进行同步,例如,一个进程有两个线程,有一个全局变量,它是共享资源,那么就必须对这个共享资源(临界资源)进行保护,当一个线程在访问它时,必须是唯一的,也就是排他性的,当这个线程访问完成后才把这个资源释放。如果,当一个线程对它访问尚未完成时,第二个线程对它进行修改,那么数据就是不安全的了,无法预测其结果。
互斥锁(互斥量)就是最简单的也是最高效的线程同步机制,通过它可以实现共享资源的保护和排他性访问。互斥锁是一个特殊的变量,它可以处于锁定状态或解锁状态,如果互斥锁是锁定状态,那么就有一个特定的线程拥有该互斥锁,如果互斥锁是解锁状态,那么就是表示没有任何线程拥有该互斥锁。当特定线程拥有了该互斥锁(未解锁前),那么任何其他的线程想要获取该互斥锁就必须等待(这些线程组成一个等待线程队列,这个队列与这个互斥锁直接相关),直到这个线程把互斥锁释放(解锁),等待的线程才被唤醒。重新竞争这个互斥锁,必定只有一个线程能获取(由线程调度策略决定),那么其他没有获取的线程就重新进入等待队列。
互斥锁相关的函数和数据类型有:
互斥锁的数据类型是:pthread_mutex_t;
互斥锁的属性数据类型是:pthread_mutexattr_t;
(1)初始化函数:
int pthread_mutex_init(pthread_mutex_t *mutex, constpthread_mutexattr_t *attr);
按参数 attr指定的属性创建一个新的互斥锁变量 mutex,如果参数 attr为 NULL,则互斥锁变量 mutex使用默认的属性。这是对动态分配的互斥锁的初始化办法,对于静态分配的互斥锁可以直接赋值初始化:
pthread_mutex_tmutex=PTHREAD_MUTEX_INITIALIZER;
任何一个互斥锁在被使用前,都必须初始化,且只能初始化一次(如果是被销毁了的互斥锁,就可以重新初始化)。
(2)销毁函数:
int pthread_mutex_destroy(pthread_mutex_t*mutex);
该函数用来释放对互斥锁分配的资源,任何互斥锁在销毁前,必须要确定没有线程正锁定着它。
(3)锁定和解锁函数:
int pthread_mutex_lock(pthread_mutex_t*mutex);
函数 pthread_mutex_lock 用来锁住互斥锁变量,如果参数 mutex所指的互斥锁已经被锁住了,那么调用的线程将挂起直到其他线程对mutex 解锁为止。
int pthread_mutex_trylock(pthread_mutex_t*mutex);
该函数企图锁住一个互斥锁,但不阻塞。
int pthread_mutex_unlock(pthread_mutex_t*mutex);
该函数用来对一个互斥锁进行解锁,如果有线程阻塞在该互斥锁上时,唤醒它们。
以上函数如果成功就返回0,如果不成功就返回一个非零的错误码。所有函数不是线程取消点,也不能被信号中断,特别要注意的是锁定函数,当线程所要锁定的互斥锁已经被别的线程锁定时,那么该线程将挂起,挂起后,不会因收到信号而返回,除非是线程终止或取消信号,或进程终止信号。这跟无名信号量不同(无名信号量请看本节第6点)。其次,互斥锁只能被短时间拥有,如果象等待输入这种持续时间不确定的情况,就不能用互斥锁。
用互斥锁来实现对共享资源的访问的简单例子(省略了错误检测):
int a=0; //全局变量
pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER;//全局变量
pthread_mutex_lock(&mutex);
a++; // criticalsection;
pthread_mutex_unlock(&mutex);
在第五节中所说的非线程安全的库函数,就可以通过互斥锁来实现成为线程安全的函数。如将上面代码段中的criticalsection部分用某库函数代替,那么就可以实现该库函数的线程安全性。
http://blog.sina.com.cn/s/blog_53a204a90100075m.html