一、互斥量:
保证同一时间只有一个线程访问数据,在线程访问数据前先对数据加锁,这样数据只能为该线程所用,其他试图对数据加锁的线程将被阻塞直到当前线程释放对该数据的锁。
如果释放互斥锁时,有多个线程阻塞,所有在该互斥锁上的阻塞线程都会变成可运行状态,第一个变成运行状态的线程可以对互斥量加锁,其他线程将会看到互斥锁依然被锁住,只能回去再次等待它重新变为可用。在这种方式下,每次只有一个线程可以向前执行。
互斥量用pthread_mutex_t数据类型来表示,在使用互斥量以前,必须首先对它进行初始化,可以设置为常量PTHREAD_MUTEX_INITIALIZER(只对静态分配的互斥量)。也可以调用pthread_mutex_init函数进行动态初始化。如果通过malloc分配互斥量,那么在释放内存以前需要调用pthread_mutex_destroy。
二、函数原型:
int pthread_mutex_init(pthread_mutex_t *mutex,const pthread_mutexattr_t *mutexattr)
功能:以动态方式初始化互斥量
参数:
mutex:要初始化的互斥量
mutexattr:指定互斥量属性,使用NULL时默认属性。(详细见下面的同步属性)
返回值:成功返货0,错误返回错误编号
注:也可以使用 phread_mutex_t mutex=PTHREAD_MUTEX_INITALIZER; 在LinuxThreads实现中,pthread_mutex_t是一个结构, 而 PTHREAD_MUTEX_INITIALIZER则是一个结构常量。
int pthread_mutex_destory(pthread_mutex_t *mutex)
功能:用于注销一个互斥锁
参数:
mutex:要注销的互斥锁
返回值:成功返回0,错误返回错误编号
注:销毁一个互斥锁即意味着释放它所占用的资源,且要求锁当前处于开发状态。由于在linux中,互斥锁并不占用任何资源,因此LinuxThreads中的 pthread_mutex_destroy()除了检查锁状态以外(锁定状态则返回EBUSY)没有其他动作。
int pthread_mutex_lock(pthread_mutex_t *mutex);
功能:对互斥量加锁,如果已经上锁,则调用线程阻塞到互斥量被解锁
参数:mutex:要加锁的互斥量
返回值:成功返回0,失败返回错误编号
注:
- 如果互斥锁类型为 PTHREAD_MUTEX_TIMED_NP,则不提供死锁检测。尝试重新锁定 互斥锁 会导致死锁。如果某个线程尝试解除锁定的 互斥锁 不是由该线程锁定或未锁定,则将产生不确定的行为。
- 如果 互斥锁 类型为PTHREAD_MUTEX_ERRORCHECK_NP,则会提供错误检查。如果某个线程尝试重新锁定的 互斥锁 已经由该线程锁定,则将返回错误。如果某个线程尝试解除锁定的 互斥锁 不是由该线程锁定或者未锁定,则将返回错误。
- 如果互斥锁类型为 PTHREAD_MUTEX_RECURSIVE_NP,则该互斥锁会保留锁定计数这一概念。线程首次成功获取互斥锁时,锁定计数会设置为 1。线程每重新锁定该 互斥锁 一次,锁定计数就增加 1。线程每解除锁定该 互斥锁 一次,锁定计数就减小 1。 锁定计数达到 0 时,该 互斥锁 即可供其他线程获取。如果某个线程尝试解除锁定的互斥锁不是由该线程锁定或者未锁定,则将返回错误。
- 如果 互斥锁 类型是PTHREAD_MUTEX_ADAPTIVE_NP,操作系统在实现它的时候,可以把这种类型自由地映射到其他类型。例如,Linux中,这种类型映射为普通的互斥量类型。
int pthread_mutex_trylock( pthread_mutex_t *mutex );
函数是pthread_mutex_lock函数的非阻塞版本。如果mutex参数所指定的互斥锁已经被锁定的话,调用pthread_mutex_trylock函数不会阻塞当前线程,而是立即返回一个值来描述互斥锁的状况。
需要注意的是,只有确保在pthread_mutex_trylock()调用成功时,即返回值为0时,才能去解锁它。
int pthread_mutex_unlock(pthread_mutex_t *mutex);
功能:释放互斥锁,与pthread_mutex_lock成对存在。
参数:mutex:要释放的互斥锁
返回值:成功返回0,失败返回错误编号
三、同步属性:
就像线程具有属性一样,线程的同步对象也有属性。
一、互斥量属性:
互斥量的属性用pthread_mutexattr_t结构表示。
int pthread_mutexattr_init(pthread_mutexattr_t *mattr);
功能:初始化一个互斥量属性
参数:
mattr:要初始化的互斥量属性
返回值:成功返回0,错误返回错误编号
值得注意的两个属性是进程共享属性和类型属性。
进程共享属性:
PTHREAD_PROCESS_PRIVATE(缺省值):表示同一个同步对象只能由同一个进程里的多个线程访问。
PTHREAD_PROCESS_SHARED:表示从多个进程共享的区域中分配的互斥量可以用于这些进程的同步。
类型属性:
- PTHREAD_MUTEX_TIMED_NP,这是缺省值,也就是普通锁。当一个线程加锁以后,其余请求锁的线程将形成一个等待队列,并在解锁后按优先级获得锁。这种锁策略保证了资源分配的公平性。
- PTHREAD_MUTEX_RECURSIVE_NP,嵌套锁,允许同一个线程对同一个锁成功获得多次,并通过多次unlock解锁。如果是不同线程请求,则在加锁线程解锁时重新竞争。
- PTHREAD_MUTEX_ERRORCHECK_NP,检错锁,如果同一个线程请求同一个锁,则返回EDEADLK,否则与PTHREAD_MUTEX_TIMED_NP类型动作相同。这样就保证当不允许多次加锁时不会出现最简单情况下的死锁。
- PTHREAD_MUTEX_ADAPTIVE_NP,适应锁,动作最简单的锁类型,仅等待解锁后重新竞争。
int pthread_mutexattrattr_destroy( pthread_mutexattr_t *attr );
功能:销毁互斥量属性对象
参数:attr:要销毁的互斥量属性
返回值:成功返回0,失败返回-1
int pthread_mutexattr_setpshared(pthread_mutexattr_t *mattr, int pshared);
功能:设置互斥量的进程共享属性
参数:
mattr:要设置的互斥量属性
pshared:要设置的进程共享属性
PTHREAD_PROCESS_PRIVATE(缺省值):表示互斥量只能由同一个进程里的多个线程访问。
PTHREAD_PROCESS_SHARED:表示从多个进程共享的区域中分配的互斥量可以用于这些进程的同步。
返回值:成功返回0,失败返回错误编号
int pthread_mutexattr_getpshared(pthread_mutexattr_t *mattr, int *pshared);
功能:获取互斥量的进程共享属性
参数:
mattr:互斥量属性
pshared:用于存放获得的互斥量进程共享属性
返回值: 成功返回0,失败返回错误编号
int pthread_mutexattr_settype(pthread_mutexattr_t *attr , int type);
功能:设置互斥量的类型属性
参数:
mattr:互斥量属性
type:要设置的类型属性
返回值: 成功返回0,失败返回错误编号
int pthread_mutexattr_gettype(pthread_mutexattr_t *attr , int *type);
功能:获取互斥量类型属性
参数:
mattr:互斥量属性
type:用于存放获得的类型属性
返回值: 成功返回0,失败返回错误编号
二、条件变量属性:
int pthread_condattr_init(pthread_condattr_t *cattr);
int pthread_condattr_destroy(pthread_condattr_t *cattr);
int pthread_condattr_setpshared(pthread_condattr_t *cattr,int pshared);
int pthread_condattr_getpshared(const pthread_condattr_t *cattr,int *pshared);
用法和互斥量属性基本一样。
例程:
#define BUFF_SIZE 128
typedef struct _global_mem_ {
char buff[BUFF_SIZE];
const int buffsize;
pthread_mutex_t mutex;
}gmem_t;
gmem_t globamem = {
.buffsize = BUFF_SIZE,
.mutex = PTHREAD_MUTEX_INITIALIZER
};
void * reader(void *arg);
void * writer(void *arg);
int main()
{
void *(*pthread_handlers[])(void *) = {
reader,
writer,
};
const int THDNO = sizeof(pthread_handlers) / sizeof(*pthread_handlers);
pthread_t tids[THDNO];
int index;
// pthread_mutex_init(&globamem.mutex, NULL);
for (index = 0; index < THDNO; index ++)
pthread_create( tids+index, NULL, pthread_handlers[index], NULL);
for (index = 0; index < THDNO; index ++)
pthread_join(tids[index], NULL);
return 0;
}
void * reader(void *arg)
{
while (1)
{
pthread_mutex_lock(&globamem.mutex);
// pthread_mutex_lock(&globamem.mutex);
printf("read: %s\n", globamem.buff);
memset(globamem.buff, 0, BUFF_SIZE);
pthread_mutex_unlock(&globamem.mutex);
sleep(1);
}
return NULL;
}
void * writer(void *arg)
{
while (1)
{
pthread_mutex_lock(&globamem.mutex);
puts("copy:");
strcpy(globamem.buff, "hello");
puts("cat");
sleep(1);
strcat(globamem.buff, "----------------------------world");
pthread_mutex_unlock(&globamem.mutex);
sleep(1);
}
return NULL;
}