线程同步
互斥锁
在线程实际运行过程中,我们经常需要多个线程保持同步。这时可以用互斥锁来完成任务(资源竞争)。可以通过使用pthread的互斥接口保护数据,在访问共享资源前对互斥量进行加锁,在访问完成后解开互斥量上的锁。
互斥量用pthread_mutex_t数据类型来表示,在使用互斥变量以前,必须先对其进行初始化,可以将其置为常量PTHREAD_MUTEX_INITIALIZER(只能用于静态分配的互斥量),也可以调用pthread_mutex_init函数进行初始化。若是动态的互斥量(如:调用malloc),就要在释放内存前先调用pthread_mutex_destroy函数。
#include <pthread.h>
int pthread_mutex_init(pthread_mutex_t *restrict mutex,
const pthread_mutexattr_t *restrict attr); //attr = NULL时,使用默认属性初始化互斥量
int pthread_mutex_destroy(pthread_mutex_t *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);
如果线程不希望被阻塞,
可以在线程中调用pthread_mutex_trylock函数对互斥量加锁。
unix环境高级编程的例子
//使用互斥锁保护数据结构
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/types.h>
struct foo
{
int f_count;
pthread_mutex_t f_lock;
};
struct foo *foo_alloc(void)
{
struct foo *fp;
if((fp = malloc(sizeof(struct foo))) != NULL)
{
fp->f_count = 1;
if(pthread_mutex_init(&fp->f_lock, NULL) != 0)
{
free(fp);
return(NULL);
}
}
return(fp);
}
void foo_hold(struct foo *fp)
{
pthread_mutex_lock(&fp->f_lock);
fp->f_count++;
pthread_mutex_unlock(&fp->f_lock);
}
void foo_rele(struct fpp *fp)
{
pthread_mutex_lock(&fp->f_lock);
if(--fp->f_count == 0)
{
pthread_mutex_unlock(&fp->f_lock);
pthread_mutex_destroy(&fp->f_lock);
free(fp);
}
else
{
pthread_mutex_unlock(&fp->f_lock);
}
}
避免死锁
如果线程试图对同一个互斥量加锁两次,那么它自身就会陷入死锁状态。当
需要
同时使用两个互斥锁时,总是让它们以相同的顺序加锁,以避免死锁,第二个互斥锁维护着一个用于跟踪foo数据结构的散列列表。这样hashlock互斥锁保护foo数据结构中的fh散列表和f_next散列链子段。foo结构中的f_lock互斥锁保护对foo结构中的其他字段的访问。
unix环境高级编程的例子
//使用两个互斥锁
#include <stdlib.h>
#include <pthread.h>
#define NHASH 29
#define HASH(fp) (((unsigned long)fp) %NHASH)
struct foo *fh[NHASH];
pthread_muxtex_t hashlock = PTHREAD_MUTEX_INITIALIZER;
struct foo
{
int f_count;
pthread_mutex_t f_lock;
struct foo *f_next;
int f_id;
};
struct foo *foo_alloc(void)
{
struct foo *fp;
int idx;
if((fp = malloc(sizeof(struct foo)))!= NULL)
{
fp->f_count = 1;
if(pthread_mutex_init(&fp->f_lock, NULL) != 0)
{
free(fp);
return(NULL);
}
idx = HASH(fp);
pthread_mutex_lock(&hashlock);
fp->f_next = fh[idx];
fh[idx] = fp->f_next;
pthread_mutex_lock(&fp->f_lock);
pthread_mutex_unlock(&hashlock);
pthread_mutex_unlock(&fp->f_lock);
}
rerutn(fp);
}
struct foo *foo_find(int id)
{
struct foo *fp;
int idx;
idx = HASH(fp);
pthread_mutex_lock(&hashlock);
for(fp = fh[idx]; fp != NULL; fp = fp->f_next)
{
if(fp->f_id == id)
{
foo_hold(fd);
break;
}
}
pthread_mutex_unlock(&hashlock);
return(fp);
}
void foo_rele(struct foo *fp)
{
struct foo *tfp;
int idx;
pthread_mutex_lock(&fp->f_lock);
if(fp->f_count == 1)
{
pthread_mutex_unlock(&fp->f_lock);
pthread_mutex_lock(&hashlock);
pthread_mutex_lock(&fp->f_lock);
if(fp->f_count != 1)
{
fp->f_count--;
pthread_mutex_unlock(&fp->f_lock);
pthread_mutex_unlock(&hashlock);
return;
}
idx = HASH(fp);
tfp = fh[idx];
if(tfp == fp)
{
fh[idx] = fp->f_next;
}
else
{
while(tfp->f_next != fp)
{
tfp = tfp->f_next;
}
tfp->f_next = fp->f_next;
}
pthread_mutex_unlock(&hashlock);
pthread_mutex_unlock(&fp->f_lock);
pthread_mutex_destroy(&fp->f_lock);
free(fp);
}
else
{
fp->f_count--;
pthread_mutex_unlock(&fp->f_lock);
}
}