2.1 Mutex
互斥锁(Mutex,Mutual Exclusive Lock),获得锁的线程可以完成“读-修改-写”的操作,然后释放锁给其它线程,没有获得锁的线程只能等待而不能访问共享数据,这样“读-修改-写”三步操作组成一个原子操作,要么都执行,要么都不执行,不会执行到中间被打断,也不会在其它处理器上并行做这个操作。
Mutex用pthread_mutex_t
类型的变量表示,可以这样初始化和销毁:
#include <pthread.h> int pthread_mutex_destroy(pthread_mutex_t *mutex); int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr); pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
返回值:成功返回0,失败返回错误号。
pthread_mutex_init
函数对Mutex做初始化,参数attr
设定Mutex的属性,如果attr
为NULL
则表示缺省属性。用pthread_mutex_init
函数初始化的Mutex可以用pthread_mutex_destroy
销毁。如果Mutex变量是静态分配的(全局变量或static
变量),也可以用宏定义PTHREAD_MUTEX_INITIALIZER
来初始化,相当于用pthread_mutex_init
初始化并且attr
参数为NULL
。Mutex的加锁和解锁操作可以用下列函数:
#include <pthread.h> int pthread_mutex_lock(pthread_mutex_t *mutex); int pthread_mutex_trylock(pthread_mutex_t *mutex); int pthread_mutex_unlock(pthread_mutex_t *mutex);
返回值:成功返回0,失败返回错误号。
一个线程可以调用pthread_mutex_lock获得Mutex,如果这时另一个线程已经调用pthread_mutex_lock获得了该Mutex,则当前线程需要挂起等待,直到另一个线程调用pthread_mutex_unlock释放Mutex,当前线程被唤醒,才能获得该Mutex并继续执行。
如果一个线程既想获得锁,又不想挂起等待,可以调用pthread_mutex_trylock,如果Mutex已经被另一个线程获得,这个函数会失败返回EBUSY,而不会使线程挂起等待。
范例:
#include <stdio.h> #include <stdlib.h> #include <pthread.h> #define LOOP 5000 int counter; pthread_mutex_t counter_mutex=PTHREAD_MUTEX_INITIALIZER; void *doit(void *p); int main(void) { pthread_t tida,tidb; pthread_create(&tida,NULL,doit,NULL); pthread_create(&tidb,NULL,doit,NULL); pthread_join(tida,NULL); printf("hahadsj;fj;salfj;salfj"); pthread_join(tidb,NULL); return 0; } void *doit(void *p) { int i,val; for(i=0;i<LOOP;i++) { pthread_mutex_lock(&counter_mutex); val=counter; printf("%x:%d\n",(unsigned int)pthread_self(),val+1); counter=val+1;10000 pthread_mutex_unlock(&counter_mutex); } return NULL; }
10000
每个Mutex有一个等待队列,一个线程要在Mutex上挂起等待,首先在把自己加入等待队列中,然后置线程状态为睡眠,然后调用调度器函数切换到别的线程。一个线程要唤醒等待队列中的其它线程,只需从等待队列中取出一项,把它的状态从睡眠改为就绪,加入就绪队列,那么下次调度器函数执行时就有可能切换到被唤醒的线程。