linux线程同步(1)-互斥量
一.概述
互斥量是线程同步的一种机制,用来保护多线程的共享资源。同一时刻,只允许一个线程对临界区进行访问。
互斥量的工作流程:创建一个互斥量,把这个互斥量的加锁调用放在临界区的开始位置,解锁调用放到临界区的结束位置。当内核优先把某个线程调度到临界区的开始位置时,线程执行这个加锁调用,并进入临界区对资源进行操作。此时其他线程再被内核调度到这里的时候,由于该互斥量已被加锁状态,得不到锁会一直阻塞在这里,导致其他线程不能进入临界区,直到刚刚那个进入临界区的线程离开临界区并执行解锁调用。
二.函数接口
1.初始化互斥量
互斥量是一个pthread_mutex_t类型的变量。
1.1:用宏常量初始化:
pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
1.2:用函数初始化:
#include <pthread.h> int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);
mutex:互斥量结构指针
attr:互斥量的属性结构指针
2.设置互斥量属性
#include <pthread.h> int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type);
attr:互斥量的属性结构指针
type:PTHREAD_MUTEX_NORMAL(默认属性),PTHREAD_MUTEX_ERRORCHECK(会进行错误检查,速度比较慢),PTHREAD_MUTEX_RECURSIVE(递归锁)。对于递归锁,同一个线程对一个递归锁加锁多次,会有一个锁计数器,解锁的时候也需要解锁这个次数才能释放该互斥量。
3.加锁与解锁
#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_lock()得不到锁会阻塞,int pthread_mutex_trylock()得不到锁会立即返回,并返回EBUSY错误。
还有一个pthread_mutex_timedlock()会根据时间来等待加锁,如果这段时间得不到锁会返回ETIMEDOUT错误!
#include <pthread.h> #include <time.h> int pthread_mutex_timedlock(pthread_mutex_t *restrict mutex, const struct timespec *restrict abs_timeout);
4.销毁互斥量
#include <pthread.h> int pthread_mutex_destroy(pthread_mutex_t *mutex);
mutex:创建的互斥量指针
三.简单例子
写个简单的例子,主线程消费,子线程生产,并模拟使用过程中可能遇到的缺点
/**
* @file pthread_mutex.c
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
/* 定义互斥量 */
pthread_mutex_t mtx;
/* 互斥量属性 */
pthread_mutexattr_t mtx_attr;
/* 全局资源 */
int money;
void err_exit(const char *err_msg)
{
printf("error:%s\n", err_msg);
exit();
}
/* 线程函数 */
void *thread_fun(void *arg)
{
)
{
/* 加锁 */
pthread_mutex_lock(&mtx);
printf("子线程进入临界区查看money\n");
)
{
money += ;
printf("子线程:money = %d\n", money);
}
/* 解锁 */
pthread_mutex_unlock(&mtx);
sleep();
}
return NULL;
}
int main(void)
{
pthread_t tid;
/* 初始化互斥量属性 */
)
err_exit("pthread_mutexattr_init()");
/* 设置互斥量属性 */
)
err_exit("pthread_mutexattr_settype()");
/* 初始化互斥量 */
)
err_exit("pthread_mutex_init()");
/* 创建一个线程 */
)
err_exit("pthread_create()");
money = ;
)
{
/* 加锁 */
pthread_mutex_lock(&mtx);
)
{
money -= ;
printf("主线程:money = %d\n", money);
}
/* 解锁 */
pthread_mutex_unlock(&mtx);
sleep();
}
;
}
主线程和子线程都对money的操作进行了互斥量保护。68行,初始化money是1000,主线程每次消耗100,子线程只有到money是0是才会生产。sleep(1)防止独占cpu,也方便打印信息。编译运行:

可以看到这里有个非常浪费资源的问题:主线程消耗money的时候,子线程它不知道什么时候才消耗完,每次内核调度到它时,它都进入临界区加锁互斥量,然后查看money,再解锁。这无意义的操作,简直是极大的浪费!有什么办法可以解决这个问题呢?它有一个好伙伴,叫条件变量。
四.死锁
假设:当线程1获取锁1,再获取锁2后才能进入临界区1,线程2获取锁2,再获取锁1才能进入临界区2。某个时刻,线程1获取了锁1,再去获取锁2的时候发现锁2已经被线程2锁住了,而线程2获取锁2后,发现锁1被线程1锁住了。这样2个线程谁也不让谁,都进不了自己的临界区,就产生了死锁现象!一般遇到这种情况常见的解决办法是:规定统一的加锁顺序。线程1和线程2都按照先锁1,再锁2。还一种就是使用pthread_mutex_trylock(),如果该函数返回EBUSY错误,就释放这个线程的所有锁,不过效率有点低。
linux线程同步(1)-互斥量的更多相关文章
- UNIX环境高级编程——线程同步之互斥量
互斥量(也称为互斥锁)出自POSIX线程标准,可以用来同步同一进程中的各个线程.当然如果一个互斥量存放在多个进程共享的某个内存区中,那么还可以通过互斥量来进行进程间的同步. 互斥量,从字面上就可以知道 ...
- 线程同步 - POSIX互斥锁
线程同步 - POSIX互斥锁 概括 本文讲解POSIX中互斥量的基本用法,从而能达到简单的线程同步.互斥量是一种特殊的变量,它有两种状态:锁定以及解锁.如果互斥量是锁定的,就有一个特定的线程持有或者 ...
- linux系统编程:线程同步-相互排斥量(mutex)
线程同步-相互排斥量(mutex) 线程同步 多个线程同一时候訪问共享数据时可能会冲突,于是须要实现线程同步. 一个线程冲突的演示样例 #include <stdio.h> #includ ...
- Linux线程同步——条件变量
互斥锁是用来给资源上锁的,而条件变量是用来等待而不是用来上锁的. 条件变量用来自动阻塞一个线程,直到某特殊情况发生为止. 通常条件变量和互斥锁同时使用. 和条件变量使用有关的几个重要函数: int p ...
- APUE学习笔记——11 线程同步、互斥锁、自旋锁、条件变量
线程同步 同属于一个进程的不同线程是共享内存的,因而在执行过程中需要考虑数据的一致性. 假设:进程有一变量i=0,线程A执行i++,线程B执行i++,那么最终i的取值是多少呢?似乎一定 ...
- Linux线程同步
1. 线程同步: 当多个控制线程共享相同的内存时,需要确保每个线程看到一致的数据视图.当某个线程可以修改变量,而其他线程也可以读取或者修改这个变量的时候,就需要对这些线程进行同步,以确保他们在访问变量 ...
- Linux 自旋锁,互斥量(互斥锁),读写锁
自旋锁(Spin Lock) 自旋锁类似于互斥量,不过自旋锁不是通过休眠阻塞进程,而是在取得锁之前一直处于忙等待的阻塞状态.这个忙等的阻塞状态,也叫做自旋. 自旋锁通常作为底层原语实现其他类型的锁. ...
- Linux 线程同步的三种方法(互斥锁、条件变量、信号量)
互斥锁 #include <cstdio> #include <cstdlib> #include <unistd.h> #include <pthread. ...
- 【转】【Linux】 临界区,互斥量,信号量,事件的区别
原文地址:http://blog.itpub.net/10697500/viewspace-612045/ Linux中 四种进程或线程同步互斥的控制方法1.临界区:通过对多线程的串行化来访问公共资源 ...
随机推荐
- linux下查找java进程占用CPU过高原因
1. 查找进程 top查看进程占用资源情况 明显看出java的两个进程22714,12406占用过高cpu. 2.查找线程 使用top -H -p <pid>查看线程占用情况 3. ...
- ASP.NET MVC Model绑定的简单应用
Model绑定是 MVC 框架根据 HTTP 请求数据创建 .NET 对象的一个过程. 一.简单类型 1.单一值
- Quartz.NET开源作业调度框架系列(二):CronTrigger
CronTriggers比SimpleTrigger更加的灵活和有用,对于比较复杂的任务触发规则,例如"每个星期天的晚上12:00"进行备份任务,SimpleTrigger就不能胜 ...
- word-wrap、white-space和word break的区别
- 总结CSS3新特性(Transition篇)
CSS 过渡(transition), 是 CSS3 规范的一部分, 用来控制 CSS 属性的变化速率. 可以让属性的变化过程持续一段时间,而不是立即生效.比如,将元素的颜色从白色改为黑色,通常这个改 ...
- android tools使用方式
我们希望在布局中显示测试的属性,而这个属性不会影响到正式代码,因此我们就需要tools这个命名空间. 首先定义:xmlns:tools="http://schemas.android.com ...
- android listview多视图嵌套多视图
笔记,listview视图总结 public class HomeEduMoreAdapter extends BaseAdapter { private final String TAG = &qu ...
- Learn RxJava
Learn RxJava http://reactivex.io/documentation/operators.html https://github.com/ReactiveX/RxJava/wi ...
- Android Property Animation动画
3.0以前,android支持两种动画模式,tween animation,frame animation,在android3.0中又引入了一个新的动画系统:property animation,这三 ...
- Android自定义ScrollView分段加载大文本数据到TextView
以下内容为原创,转载时请注明链接地址:http://www.cnblogs.com/tiantianbyconan/p/3311658.html 这是我现在碰到的一个问题,如果需要在TextView中 ...