为了防止出现线程某甲试图访 问一共享变量时,线程某乙正在对其进行修改。引入了互斥量
互斥量 (保护对共享变量的访问)
1.概念
2.状态
3.特点
互斥量的分配
互斥量既可以像静态变量那样分配,也可以在运行时动态创建
1.静态分配
2.动态分配
注:
1.初始化一个业已初始化的互斥量将导致未定义的行为
2
- 动态分配于堆中的互斥量。例如,动态创建针对某一结构的链表,表中每个结构都包含一个 pthread_mutex_t 类型的字段来存放互斥量,借以保护对该结构的访问。
- 互斥量是在栈中分配的自动变量。
- 初始化经由静态分配,且不使用默认属性的互斥量。
加锁和解锁互斥量
函数原型
1.创建互斥锁
pthread_mutex_t mtx;
//第二个参数为 NULL,互斥锁的属性会设置为默认属性
pthread_mutex_init(&mtx, NULL);
3.获取互斥锁
pthread_mutex_lock(&mtx);
5.非阻塞调用
int err = pthread_mutex_trylock(&mtx);
if(0 != err) {
if(EBUSY == err) {
//The mutex could not be acquired because it was already locked.
}
}
6.超时调用
struct timespec abs_timeout;
abs_timeout.tv_sec = time(NULL) + 1;
abs_timeout.tv_nsec = 0;
int err = pthread_mutex_timedlock(&mtx, &abs_timeout);
if(0 != err) {
if(ETIMEDOUT == err) {
//The mutex could not be locked before the specified timeout expired.
}
}
struct timespec
{
__time_t tv_sec; /* Seconds. */
long int tv_nsec; /* Nanoseconds. */
};
7、释放互斥锁
pthread_mutex_unlock(&mtx);
8、销毁线程锁
pthread_mutex_destroy(&mtx)
互斥量的死锁
当超过一个线程加锁同一组互斥量时,就有可能发生死锁。
例,每个线程都成功地锁住一个互斥量,接着试图对已为另一线程锁定的互斥量加锁。
两个线程将无限期等待
有两种解决方法
注:对共享资源操作前一定要获得锁。
完成操作以后一定要释放锁。
尽量短时间地占用锁。
如果有多锁, 如获得顺序是ABC连环扣, 释放顺序也应该是ABC。
线程错误返回时应该释放它所获得的锁。
例子
保护fp指向文件中数的累加正常进行
static pthread_mutex_t mut=PTHREAD_MUTEX_INITIALIZER;
void *thr_prime(void *p)
{
FILE *fp;
char linebuf[linesize];
fp =fopen(fname,"r+"); //多个线程之间相撞拿到 同一个fp 开始覆盖写操作
if(fp == NULL)
{
perror("fopen");
exit(-1);
}
//加锁
pthread_mutex_lock(&mut);
fgets(linebuf,linesize,fp);
fseek(fp,0,SEEK_SET);
fprintf(fp,"%d\n",atoi(linebuf)+1);
//解锁
pthread_mutex_unlock(&mut);
fclose(fp);
pthread_exit(NULL);
}
int main()
{
int err,i;
pthread_t tid[thrnum];
//main 线程 进行创建线程
for(i=0 ; i<=thrnum ;i++)
{
err =pthread_create(tid + i ,NULL,thr_prime,NULL);
if(err)
{
fprintf(stderr,"pthread_creat():%s\n",strerror(err));
exit(1);
}
}
//为线程收尸
for(i =0 ; i<=thrnum ;i++)
{
pthread_join(tid[i],NULL);
}
pthread_mutex_destroy(&mut);
exit(0);
}