linux学习笔记之线程同步机制
一、基础知识。
1:线程同步机制:互斥量,读写锁,条件变量,自旋锁,屏障。
1,互斥量:每个进程访问被互斥量保护的资源时,都需要先对互斥量进行判断。
1)互斥量重要属性:进程共享属性,健壮属性,类型属性。
2)部分系统 不支持 进程共享属性
3)对互斥量重复加锁会导致死锁。
2,读写锁。
1)读写锁有3种状态:读模式加锁,写模式加锁,未加锁。
1-写加锁模式:任何加锁都会被阻塞。
2-读加锁模式:读模式加锁的任何线程都可以得到访问权,同时添加一个读模式锁。但,写模式加锁会被阻塞。
3-在读模式下,线程试图写加锁,会阻塞:1 线程本身 和 2 之后的读模式。保证写模式不会被一指阻塞。
2)递归锁可能很难处理,只有在无其他反感时,才考虑。
3)读写锁支持的唯一属性时:进程共享属性。
3,条件变量:条件变量是线程的另外一种同步机制。它本身由互斥量保护。线程在改变条件状态之前必须首先锁住互斥量。
1)条件变量支持属性:进程共享属性 和 时钟属性。
4,自旋锁。
1)和互斥量类似。不同点在于:获取锁之前,线程一直处于 忙等(自旋)阻塞状态。(互斥量使用休眠阻塞)
2)只能用于:锁持有时间短,线程不喜欢在重新调度上花费太多成本。
3)在非抢占式内核中非常有用:因为它会阻塞中断。这样中断处理程序就不会让系统陷入死锁状态。
5,屏障。
1)类似于里程碑:用户协调多个线程并行工作的同步机制。它允许每个线程等待,直到所有合作的线程都到达某一个点(里程碑)。
2)屏障属性只有 进程共享属性。
3)PTHREAD_PROCESS_SHARED(多进程共享) 和 PTHREAD_PROCESS_PROVATE(单进程,不共享)
二、相关函数。
1:信号。
发送信号
int kill(pid_t pid, int signo ); 发送信号给进程/进程组
// 1 参数pid:>0 ID=pid的进程中;0 同进程组的所有进程;<0 进程组ID==pid绝对值 的进程组中;-1 所有能够发送的进程。
int raise( int signo ); 发送信号给自身。
信号集处理函数
int sigemptyset( sigset_t *set );
int sigfillset( sigset_t *set );
int sigaddset( sigset_t *set, int signo );
int sigdelset( sigset_t *set, int signo );
int sigismember( sigset_t *set, int signo );
信号屏蔽字。
int sigprocmask( int how, const sigset_t *restrict set, sigset_t *restrict oset ); // 检测和更改,或同时检测+更改进程的信号屏蔽字。
int sigpending( sigset_t *set ); // 返回一个信号集。
int sigaction( int signo, const struct sigaction *restrict act, struct sigaction *restrict oact ); // 检测/修改与指定信号相关联的处理动作
int sigsupend( const sigset_t *sigmask ); // 作用:通过参数设置信号屏蔽字。
信号跳转函数。
int sigsetjmp( sigjmp_buf env, int savemask ); // 设置信号跳转点。
void siglongjmp( sigjmp_buf env, int val ); // 执行跳转操作,参数val为跳转点返回值。
异常终止函数。
void abort( void ); // 使程序异常终止。
// 1 使用此函数,会将SIGABRT信号发送给调用进程。进程不能忽略此信号
// 2 发送SIGABRT信号,进程可以先执行清理操作,然后再终止进程。
线程休眠函数。
unsigned int sleep( unsigned int seconds );
int nanosleep( const struct timespec *reqtp, struct timespec *remtp ); // 提供纳妙级精度。
int clock_nanosleep( clockid_t clock_id, int flags, const struct timespec *reqtp, struct timespec *remtp ); // 多系统时钟情况下,使用相对于特定时钟的延迟时间来挂起调用进程。
int sigqueue( pid_t pid, int signo, const union sigval value ); // 信号队列,可以将信号发送到一个进程的信号队列中。部分操作系统支持此功能。
// 1 可能使休眠终止的情形:调用进程捕捉到一个信号并从信号处理程序返回。
2:互斥量。
初始化。
PTHREAD_MUTEX_INITIALIZER //静态分配方式。
int pthread_mutex_init( pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr ); // 动态分配内存方式
// 1 使用默认初始化,参数attr设置为NULL。
类析构函数(释放内存前当用)。
int pthread_mutex_destroy( pthread_mutex_t *mutex );
加锁,尝试性加锁,超时锁,解锁
int pthread_mutex_lock( pthread_mutex_t *mutex ); // 如果已经加锁的互斥量,会阻塞线程,直到互斥量解锁。
int pthread_mutex_trylock( pthread_mutex_t *mutex ); //trylock尝试上锁失败后,会返回EBUSY。而不会阻塞。
int pthread_mutex_timedlock( pthread_mutex_t *restrict mutex, const struct timespec *restrict tsptr ); //超时返回:ETIMEDOUT
int pthread_mutex_unlock( pthread_mutex_t *mutex );
// 1 如果线程试图对同一互斥量加锁两次,则线程会陷入死锁状态。。
// 2 超时锁参数tsptr 表示是 绝对时间(即具体时间点,而不是时间段)
3:互斥量属性相关函数。
1 初始化和类析构函数。
int pthread_mutexattr_init( pthread_mutexattr_t *attr );
int pthread_mutexattr_destroy( pthread_mutexattr_t *attr );
2 获取/设置 进程共享属性。
int pthread_mutexattr_getshared( const pthread_mutexattr_t *restrict attr, int *restrict pshared );
int pthread_mutexattr_setshared( pthread_mutexattr_t *attr, int *pshared );
3 获取/设置 健壮属性
int pthread_mutexattr_getrobust( const pthread_mutexattr_t *restrict attr, int *restrict robust );
int pthread_mutexattr_setrobust( pthread_mutexattr_t *attr, int *robust );
4 解锁前,使属性状态统一。
int pthread_mutexattr_consistent( pthead_mutex_t *mutex );
5 获取/设置 类型属性
int pthread_mutexattr_gettype( const pthread_mutexattr_t *restrict attr, int *restrict type );
int pthread_mutexattr_settype( pthread_mutexattr_t *attr, int *type );
4:读写锁
初始化。
int pthread_rwlock_init( pthread_rwlock_t *restrict rwlock, const pthread_rwlockattr_t *restrict attr );
// 1 使用默认初始化,参数attr设置为NULL。
类析构函数(释放内存前当用)。
int pthread_rwlock_destroy( pthread_rwlock_t *rwlock );
读加锁,尝试读,超时版读,写加锁,尝试写,超时版写,解锁。
int pthread_rwlock_rdlock( pthread_rwlock_t *rwlock );
int pthread_rwlock_tryrdlock( pthread_rwlock_t *rwlock );
int pthread_rwlock_timedrdlock( pthread_rwlock_t *rwlock, const struct timespec *restrict tsptr );
int pthread_rwlock_wrlock( pthread_rwlock_t *rwlock );
int pthread_rwlock_trywrlock( pthread_rwlock_t *rwlock );
int pthread_rwlock_timedwrlock( pthread_rwlock_t *rwlock, const struct timespec *restrict tsptr );
int pthread_rwlock_unlock( pthread_rwlock_t *rwlock );
// 1 读加锁有次数限制。
// 2 尝试版本,出错返回:EBUSY。
// 3 超时版本,出错返回:ETIMEDOUT。超时时间 为 绝对时间。
获取/设置 进程共享属性。
int pthread_rwlockattr_getpshared( const pthread_rwlockattr_t *restrict attr, int *restrict pshared );
int pthread_rwlockattr_setpshared( pthread_rwlockattr_t *attr, int *pshared );
5:条件变量。
初始化。
int pthread_cond_init( pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr );
// 1 使用默认初始化,参数attr设置为NULL。
类析构函数(释放内存前当用)。
int pthread_cond_destroy( pthread_cond_t *cond );
等待条件为真,超时版本。
int pthread_cond_wait( pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex ); //此函数可以保证线程一定可以进入条件等待队列中。
int pthread_cond_timedwait( pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex, const struct timespec *restrict tsptr );
// 1 将加锁互斥量传入,然后将调用线程放入条件队列中,再解锁互斥量。等wait函数返回后,互斥量再加锁。
// 2 超时返回:ETIMEDOUT
唤醒等待条件的线程。
int pthread_cond_signal( pthread_cond_t *cond ); // 最少唤醒一个线程。
int pthread_cond_broadcast( pthread_cond_t *cond ); // 唤醒全部线程。
// 1 需要注意:要等条件状态改变以后,在使用这两个函数!!!
条件属性的初始化和类析构函数。
int pthread_condattr_init( pthread_condattr_t *attr );
int pthread_condattr_destroy( pthread_condattr_t *attr );
获取/设置 进程共享属性。
int pthread_condattr_getpshared( const pthread_condattr_t *restrict attr, int *restrict pshared );
int pthread_condattr_setpshared( pthread_condattr_t *attr, int *pshared );
获取/设置 时钟属性。
int pthread_condattr_getclock( const pthread_condattr_t *restrict attr, clockid)t *restrict clock_id );
int pthread_condattr_setclock( pthread_condattr_t *attr, clockid)t *clock_id );
6:自旋锁。
1 初始化,类析构函数(释放内存前使用)
int pthread_spin_init( pthread_spinlock_t *lock, int pshared );
int pthread_spin_destroy( pthread_spinlock_t *lock );
2 加锁,尝试性加锁,解锁。
int pthread_spin_lock( pthread_spinlock_t *lock );
int pthread_spin_trylock( pthread_spinlock_t *lock );
int pthread_spin_unlock( pthread_spinlock_t *lock );
7:屏障。
初始化,类析构函数(释放内存前使用)
int pthread_barrier_init( pthread_barrier_t *restrict barrier, const pthread_barrierattr_t *restrict attr, unsigned int count );
int pthread_barrier_destroy( pthread_barrier_t *barrier );
// 1 参数count表示需要多少个线程达到此节点后,才可以继续运行。count设置后不会改变。
当前线程已完成,等待其他线程。
int pthread_barrier_wait( pthread_barrier_t *barrier ); // 如未满足count数,则此线程进行休眠。
初始化 和 类析构函数。
int pthread_barrierattr_init( pthread_barrierattr_t *attr );
int pthread_barrierattr_destroy( pthread_barrierattr_t *attr );
获取/设置 进程共享属性。
int pthread_barrierattr_getpshared( const pthread_barrierattr *restrict attr, int *restrict pshared );
int pthread_barrierattr_setpshared( pthread_barrierattr *attr, int pshared );
三、
linux学习笔记之线程同步机制的更多相关文章
- Linux学习笔记21——线程同步的两种方式
一 用信号量同步 1 信号量函数的名字都以sem_开头,线程中使用的基本信号量函数有4个 2 创建信号量 #include<semaphore.h> int sem_init(sem_t ...
- linux学习笔记之线程
线程同步机制:http://www.cnblogs.com/zheng39562/p/4270019.html 一.基础知识 1:基础知识. 1,线程需要的信息有:线程ID,寄存器,栈,调度优先级和策 ...
- APUE学习笔记——11 线程同步、互斥锁、自旋锁、条件变量
线程同步 同属于一个进程的不同线程是共享内存的,因而在执行过程中需要考虑数据的一致性. 假设:进程有一变量i=0,线程A执行i++,线程B执行i++,那么最终i的取值是多少呢?似乎一定 ...
- APUE 学习笔记(八) 线程同步
1. 进程的所有信息对该进程内的所有线程都是共享的 包括 可执行的程序文本.程序全局内存.堆内存以及文件描述符 线程包含了表示进程内执行环境必需的信息,包括线程ID.寄存器值.栈.调度优先级和策略.信 ...
- C#学习笔记之线程 - 同步上下文
同步上下文(Synchronization Contexts) 手动使用锁的一个替代方案是去声明锁.通过派生ContextBoundObject和应用Synchronization属性,你告诉CLR自 ...
- Linux下C的线程同步机制
C里提供了保证线程安全性的三种方法: (添加头文件#include<pthread.h>,pthread 库不是 Linux 系统默认的库,连接时需要使用静态库 libpthread.a, ...
- Linux学习笔记22——线程属性(转)
本文来自博客园:http://www.cnblogs.com/yc_sunniwell/archive/2010/06/24/1764204.html 一.线程属性线程具有属性,用pthread_at ...
- Linux程序设计学习笔记----多线程编程线程同步机制之相互排斥量(锁)与读写锁
相互排斥锁通信机制 基本原理 相互排斥锁以排他方式防止共享数据被并发訪问,相互排斥锁是一个二元变量,状态为开(0)和关(1),将某个共享资源与某个相互排斥锁逻辑上绑定之后,对该资源的訪问操作例如以下: ...
- Java分享笔记:创建多线程 & 线程同步机制
[1] 创建多线程的两种方式 1.1 通过继承Thread类创建多线程 1.定义Thread类的子类,重写run()方法,在run()方法体中编写子线程要执行的功能. 2.创建子线程的实例对象,相当于 ...
随机推荐
- MJExtension(JSON到数据模型的自动转换)
整理自:http://www.jianshu.com/p/93c242452b9b. 1.MJExtension的功能 字典-->模型 模型-->字典 字典数组-->模型数组 模型数 ...
- QT错误:collect2:ld returned 1 exit status
1.编译成功的例子在后台执行,有时一闪而过,如果再次build ,则会提示上述错误. 解决方法:打开任务管理器,找到相应的exe进程,关闭即可: 或者直接关闭QtCreator. 2.没有编译成功的 ...
- kinect
1.学习资料 http://blog.csdn.net/dustpg/article/details/37982311 https://github.com/mdkus/kinect-mssdk-op ...
- tuple只有一个元素的时候,必须要加逗号
In [1]: a = (1) In [2]: a Out[2]: 1 In [3]: a = (1,) In [4]: a Out[4]: (1,) 这是因为括号()既可以表示tuple,又可以表示 ...
- 通过yocto给p1010rdb定制linux,并启动linux
一.通过yocto定制linux 1.安装yocto yocto只能在非root用户下编译,所以先新建一个用户. useradd chen passwd -d chen 重启电脑进入chen用户. ...
- Html 编码 queryUrl = encodeURI(queryUrl);
Html 编码 queryUrl = encodeURI(queryUrl);
- linux vim 常用命令
一. VIM高亮 进入vim后,在普通模式下输入如下命令,开启php代码高亮显示 :syntax enable :source $VIMRUNTIME/syntax/php.vim二. VI常用命令_ ...
- 查看oracle中的中文所占字节数
select userenv('language') from dual 显示:SIMPLIFIED CHINESE_CHINA.ZHS16GBK 表示一个汉字占用两个字节. 显示:SIMPLIFIE ...
- [置顶] SPL讲解(4)--Criteria操作篇
概念 以前一篇文章中,描述了实体Entity的操作,很明显,仅仅实体的操作是远远不够的.如:我们经常会根据查询条件从数据库中获取记录集并绑定到DataGrid上,会根据条件进行批量的Update和De ...
- eclipse的优化 gc.log
原帖:http://www.javaeye.com/topic/756538 性能优化从身边做起. 首先建立评估体系,将workspace里所有的项目close掉,关闭eclipse.优化的用例就是启 ...