在线程实际运行过程中,我们经常需要多个线程保持同步。这时可以用互斥锁来完成任务;互斥锁的使用过程中,主要有pthread_mutex_init,pthread_mutex_destory,pthread_mutex_lock,pthread_mutex_unlock这几个函数以完成锁的初始化,锁的销毁,上锁和释放锁操作。
一,锁的创建
锁可以被动态或静态创建,可以用宏PTHREAD_MUTEX_INITIALIZER来静态的初始化锁,采用这种方式比较容易理解,互斥锁是pthread_mutex_t的结构体,而这个宏是一个结构常量,如下可以完成静态的初始化锁:
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
另外锁可以用pthread_mutex_init函数动态的创建,函数原型如下:
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t * attr)
二,锁的属性
互斥锁属性可以由pthread_mutexattr_init(pthread_mutexattr_t *mattr);来初始化,然后可以调用其他的属性设置方法来设置其属性;
互斥锁的范围:可以指定是该进程与其他进程的同步还是同一进程内不同的线程之间的同步。可以设置为PTHREAD_PROCESS_SHARE和PTHREAD_PROCESS_PRIVATE。默认是后者,表示进程内使用锁。可以使用int pthread_mutexattr_setpshared(pthread_mutexattr_t *mattr, int pshared)
pthread_mutexattr_getshared(pthread_mutexattr_t *mattr,int *pshared)
用来设置与获取锁的范围;
互斥锁的类型:有以下几个取值空间:
PTHREAD_MUTEX_TIMED_NP,这是缺省值,也就是普通锁。当一个线程加锁以后,其余请求锁的线程将形成一个等待队列,并在解锁后按优先级获得锁。这种锁策略保证了资源分配的公平性。
PTHREAD_MUTEX_RECURSIVE_NP,嵌套锁,允许同一个线程对同一个锁成功获得多次,并通过多次unlock解锁。如果是不同线程请求,则在加锁线程解锁时重新竞争。
PTHREAD_MUTEX_ERRORCHECK_NP,检错锁,如果同一个线程请求同一个锁,则返回EDEADLK,否则与PTHREAD_MUTEX_TIMED_NP类型动作相同。这样就保证当不允许多次加锁时不会出现最简单情况下的死锁。
PTHREAD_MUTEX_ADAPTIVE_NP,适应锁,动作最简单的锁类型,仅等待解锁后重新竞争。
可以用
pthread_mutexattr_settype(pthread_mutexattr_t *attr , int type)
pthread_mutexattr_gettype(pthread_mutexattr_t *attr , int *type)
获取或设置锁的类型。
三,锁的释放
调用pthread_mutex_destory之后,可以释放锁占用的资源,但这有一个前提上锁当前是没有被锁的状态。
四,锁操作
对锁的操作主要包括加锁 pthread_mutex_lock()、解锁pthread_mutex_unlock()和测试加锁 pthread_mutex_trylock()三个。
int pthread_mutex_lock(pthread_mutex_t *mutex)
int pthread_mutex_unlock(pthread_mutex_t *mutex)
int pthread_mutex_trylock(pthread_mutex_t *mutex)
pthread_mutex_trylock()语义与pthread_mutex_lock()类似,不同的是在锁已经被占据时返回EBUSY而不是挂起等待
五,锁的使用
- #include <pthread.h>
- #include <stdio.h>
- pthread_mutex_t mutex ;
- void *print_msg(void *arg){
- int i=0;
- pthread_mutex_lock(&mutex);
- for(i=0;i<15;i++){
- printf("output : %d\n",i);
- usleep(100);
- }
- pthread_mutex_unlock(&mutex);
- }
- int main(int argc,char** argv){
- pthread_t id1;
- pthread_t id2;
- pthread_mutex_init(&mutex,NULL);
- pthread_create(&id1,NULL,print_msg,NULL);
- pthread_create(&id2,NULL,print_msg,NULL);
- pthread_join(id1,NULL);
- pthread_join(id2,NULL);
- pthread_mutex_destroy(&mutex);
- return 1;
- }
将会一个线程一个线程的执行。
1. 互斥锁创建
有两种方法创建互斥锁,静态方式和动态方式。POSIX定义了一个宏PTHREAD_MUTEX_INITIALIZER来静态初始化互斥锁,方法如下:
pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER;
在LinuxThreads实现中,pthread_mutex_t是一个结构,而PTHREAD_MUTEX_INITIALIZER则是一个结构常量。
动态方式是采用pthread_mutex_init()函数来初始化互斥锁,API定义如下:
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr)
其中mutexattr用于指定互斥锁属性(见下),如果为NULL则使用缺省属性。
pthread_mutex_destroy ()用于注销一个互斥锁,API定义如下:
int pthread_mutex_destroy(pthread_mutex_t *mutex)
销毁一个互斥锁即意味着释放它所占用的资源,且要求锁当前处于开放状态。由于在Linux中,互斥锁并不占用任何资源,因此LinuxThreads中的 pthread_mutex_destroy()除了检查锁状态以外(锁定状态则返回EBUSY)没有其他动作。
2. 互斥锁属性
互斥锁的属性在创建锁的时候指定,在LinuxThreads实现中仅有一个锁类型属性,不同的锁类型在试图对一个已经被锁定的互斥锁加锁时表现不同。当前(glibc2.2.3,linuxthreads0.9)有四个值可供选择:
* PTHREAD_MUTEX_TIMED_NP,这是缺省值,也就是普通锁。当一个线程加锁以后,其余请求锁的线程将形成一个等待队列,并在解锁后按优先级获得锁。这种锁策略保证了资源分配的公平性。
* PTHREAD_MUTEX_RECURSIVE_NP,嵌套锁,允许同一个线程对同一个锁成功获得多次,并通过多次unlock解锁。如果是不同线程请求,则在加锁线程解锁时重新竞争。
* PTHREAD_MUTEX_ERRORCHECK_NP,检错锁,如果同一个线程请求同一个锁,则返回EDEADLK,否则与PTHREAD_MUTEX_TIMED_NP类型动作相同。这样就保证当不允许多次加锁时不会出现最简单情况下的死锁。
* PTHREAD_MUTEX_ADAPTIVE_NP,适应锁,动作最简单的锁类型,仅等待解锁后重新竞争。
3. 锁操作
锁操作主要包括加锁 pthread_mutex_lock()、解锁pthread_mutex_unlock()和测试加锁 pthread_mutex_trylock()三个,不论哪种类型的锁,都不可能被两个不同的线程同时得到,而必须等待解锁。对于普通锁和适应锁类型,解锁者可以是同进程内任何线程;而检错锁则必须由加锁者解锁才有效,否则返回EPERM;对于嵌套锁,文档和实现要求必须由加锁者解锁,但实验结果表明并没有这种限制,这个不同目前还没有得到解释。在同一进程中的线程,如果加锁后没有解锁,则任何其他线程都无法再获得锁。
int pthread_mutex_lock(pthread_mutex_t *mutex)
int pthread_mutex_unlock(pthread_mutex_t *mutex)
int pthread_mutex_trylock(pthread_mutex_t *mutex)
pthread_mutex_trylock()语义与pthread_mutex_lock()类似,不同的是在锁已经被占据时返回EBUSY而不是挂起等待。
一、 pthread_mutex 家庭成员:
1.int pthread_mutex_init
(pthread_mutex_t *mutex , pthread_mutexattr_t * attr );
Description
The pthread_mutex_init function initializes the given mutex with the given attributes. Ifattr is null, then the default attributes are used.
2. int pthread_mutex_destroy
(pthread_mutex_t *mutex );
Description
The pthread_mutex_destroy function destroys the given mutex. If the mutex is already destroyed, thenerrno is set to EINVAL. If the mutex is locked, then errno is set to EBUSY.
3.int pthread_mutex_lock
(pthread_mutex_t *mutex );
Description
The pthread_mutex_lock function locks the given mutex. If the mutex is already locked, then the calling thread blocks until the thread that currently holds the mutex unlocks it.
4.int pthread_mutex_trylock
(pthread_mutex_t *mutex );
Description
The pthread_mutex_trylock function tries to lock the given mutex. If the mutex is already locked, the function returns without waiting for the mutex to be unlocked.
Returns
The pthread_mutex_trylock function returns zero if the call is successful, otherwise it setserrno to EINVAL and returns -1.
5.int pthread_mutex_unlock
(pthread_mutex_t *mutex );
Description
The pthread_mutex_unlock function unlocks the given mutex.
二、成员作用
1. 互斥锁的初始化和销毁
.初始化有两种初始化方式:
a. 对于静态分配的互斥锁一半用宏赋值的方式初始化
eg:static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
b. 对于动态分配的互斥锁(如调用malloc)或分配在共享内存中,则必须调用
pthread_mutex_init(pthread_mutex*mutex, pthread_mutexattr_t *mutexattr)函数来进行初始化。
动态分配释放例子:
pthread_mutex_init(*mutex ,*attr);
pthread_mutex_destory(*mutex)
pthread_mutexattr_init(*attr)
pthread_mutexattr_destory(*attr)动态分配的代码:
pthread_mutex_t
lock=(pthread_mutex_t *)malloc(sizeof(szieof(pthread_mutex_t)));
pthread_mutex_init(lock ,NULL);
. 互斥锁摧毁
pthread_mutex_destory(lock);
free(lock);
销毁一个互斥锁即意味着释放它所占用的资源,且要求锁当前处于开放状态。由于在Linux中,互斥锁并不占用任何资源,因此LinuxThreads中的 pthread_mutex_destroy()除了检查锁状态以外(锁定状态则返回EBUSY)没有其他动作。
2. 互斥锁上锁、尝试上锁和解锁
要对公共变量进行上锁来进行保护,必须最少要上两个锁以上,换句话说就得调用pthread_mutex_lock()函数两次以上,否则,只是上一个锁会达不到相应的效果。尝试上锁pthread_mutex_trylock()和pthread_mutex_lock()的区别是:后者会阻塞等待另外一个锁被解锁;前者尝试去加锁,如果不成功就返回非0,如果成功返回0,不会产生阻塞。
每次上锁之后,一定要解锁,否则会造成程序一直在阻塞状态。
三、代码讲解:
代码说明1:互斥锁基本应用
#include<stdio.h>
#include<pthread.h>
#include"unistd.h"
pthread_mutex_tmutex = PTHREAD_MUTEX_INITIALIZER;
intcount = 0;
void*consume( void *arg)
{
while(1 )
{
pthread_mutex_lock(&mutex );
printf("************************consumebegin lock\n");
printf("************************consumed%d\n",count );
sleep(2);
count++;
printf("************************consumed%d\n",count);
printf("************************consumeover lock\n");
pthread_mutex_unlock(&mutex );
printf("************************I'mout of pthread_mutex\n");
sleep(1);
}
}
void* produce( void * arg )
{
while(1 )
{
pthread_mutex_lock(&mutex );
printf("productbegin lock\n");
printf("Produced %d\n", count );
printf("productover lock\n");
pthread_mutex_unlock(&mutex );
printf("I'mout of pthread_mutex\n");
sleep(1);
}
}
intmain( void )
{
pthread_tthread1,thread2;
pthread_create(&thread1, NULL, &produce, NULL );
pthread_create(&thread2, NULL, &consume, NULL );
pthread_join(thread1,NULL);
pthread_join(thread2,NULL);
return0;
}
结果显示:
[elbort@elborttest1]$ gcc -Wall -lpthread -o test test.c
[elbort@elborttest1]$ ./test
productbegin lock
Produced0
productover lock
I'mout of pthread_mutex
************************consumebegin lock
************************consumed0
/*中间等待了2秒但是product线程没有执行|*/
************************consumed1
************************consumeover lock
************************I'mout of pthread_mutex
productbegin lock
Produced1
productover lock
I'mout of pthread_mutex
************************consumebegin lock
************************consumed1
************************consumed2
************************consumeover lock
************************I'mout of pthread_mutex
productbegin lock
Produced2
productover lock
I'mout of pthread_mutex
/************************************************************************/
代码说明2:单一调用互斥锁没效果
void*consume( void *arg)
{
while(1 )
{
pthread_mutex_lock(&mutex );
printf("************************consumebegin lock\n");
printf("************************consumed%d\n",count );
sleep(2);
count++;
printf("************************consumed%d\n",count);
printf("************************consumeover lock\n");
pthread_mutex_unlock(&mutex );
printf("************************I'mout of pthread_mutex\n");
sleep(1);
}
}
void* produce( void * arg )
{
while(1 )
{
count=count+5;
printf("Produced %d\n", count );
sleep(1);
}
}
intmain( void )
{
pthread_tthread1,thread2;
pthread_create(&thread1, NULL, &produce, NULL );
pthread_create(&thread2, NULL, &consume, NULL );
pthread_join(thread1,NULL);
pthread_join(thread2,NULL);
return0;
}
~
~
结果说明:
[elbort@elborttest1]$ ./test
Produced5
************************consumebegin lock
************************consumed5
Produced10 //线程comsume被中断,conut的值被线程product修改
************************consumed11
************************consumeover lock
************************I'mout of pthread_mutex
/********************************************************/
代码说明3:pthread_mutex_trylock作用
intcount = 0;
void*consume( void *arg)
{
while(1 )
{
pthread_mutex_lock(&mutex );
printf("************************consumebegin lock\n");
printf("************************consumed%d\n",count );
sleep(2);
count++;
printf("************************consumed%d\n",count);
printf("************************consumeover lock\n");
pthread_mutex_unlock(&mutex );
printf("************************I'mout of pthread_mutex\n");
sleep(1);
}
}
void* produce( void * arg )
{
while(1 )
{
if(pthread_mutex_trylock(&mutex ) == 0)
{
printf("productbegin lock\n");
count++;
printf("Produced %d\n", count );
printf("productover lock\n");
pthread_mutex_unlock(&mutex );
printf("I'mout of pthread_mutex\n");
sleep(1);
}
else
{
printf("Ihave try!But i can lock the mutex!\n");
sleep(1);
}
}
}
intmain( void )
{
pthread_tthread1,thread2;
pthread_create(&thread1, NULL, &produce, NULL );
pthread_create(&thread2, NULL, &consume, NULL );
pthread_join(thread1,NULL);
pthread_join(thread2,NULL);
return0;
}
结果显示:
[elbort@elborttest1]$ ./test
************************consumebegin lock
************************consumed0
Ihave try!But i can lock the mutex!
Ihave try!But i can lock the mutex!
************************consumed1
************************consumeover lock
************************I'mout of pthread_mutex
productbegin lock
Produced2
productover lock
I'mout of pthread_mutex
************************consumebegin lock
************************consumed2
Ihave try!But i can lock the mutex!
Ihave try!But i can lock the mutex!
************************consumed3
************************consumeover lock
************************I'mout of pthread_mutex
productbegin lock
Produced4
productover lock
I'mout of pthread_mutex