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:信号。

1 发送信号
  int kill(pid_t pid, int signo ); 发送信号给进程/进程组
  // 1 参数pid:>0 ID=pid的进程中;0 同进程组的所有进程;<0 进程组ID==pid绝对值 的进程组中;-1 所有能够发送的进程。
  int raise( int signo ); 发送信号给自身。
2 信号集处理函数
  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 );
3 信号屏蔽字。
  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 ); // 作用:通过参数设置信号屏蔽字。
4 信号跳转函数。
  int sigsetjmp( sigjmp_buf env, int savemask );  // 设置信号跳转点。
  void siglongjmp( sigjmp_buf env, int val );  // 执行跳转操作,参数val为跳转点返回值。
5 异常终止函数。
  void abort( void ); // 使程序异常终止。
  // 1 使用此函数,会将SIGABRT信号发送给调用进程。进程不能忽略此信号
  // 2 发送SIGABRT信号,进程可以先执行清理操作,然后再终止进程。
6 线程休眠函数。
  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:互斥量。

1 初始化。
  PTHREAD_MUTEX_INITIALIZER //静态分配方式。
  int pthread_mutex_init( pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr );  // 动态分配内存方式
  // 1 使用默认初始化,参数attr设置为NULL。
2 类析构函数(释放内存前当用)。
  int pthread_mutex_destroy( pthread_mutex_t *mutex );
3 加锁,尝试性加锁,超时锁,解锁
  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:读写锁

1 初始化。
  int pthread_rwlock_init( pthread_rwlock_t *restrict rwlock, const pthread_rwlockattr_t *restrict attr );
  // 1 使用默认初始化,参数attr设置为NULL。
2 类析构函数(释放内存前当用)。
  int pthread_rwlock_destroy( pthread_rwlock_t *rwlock );
3 读加锁,尝试读,超时版读,写加锁,尝试写,超时版写,解锁。
  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。超时时间 为 绝对时间。
4 获取/设置 进程共享属性。
  int pthread_rwlockattr_getpshared( const pthread_rwlockattr_t *restrict attr, int *restrict pshared );
  int pthread_rwlockattr_setpshared( pthread_rwlockattr_t *attr, int *pshared );

 5:条件变量。

1 初始化。
  int pthread_cond_init( pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr );
  // 1 使用默认初始化,参数attr设置为NULL。
2 类析构函数(释放内存前当用)。
  int pthread_cond_destroy( pthread_cond_t *cond );
3 等待条件为真,超时版本。
  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
4 唤醒等待条件的线程。
  int pthread_cond_signal( pthread_cond_t *cond );  // 最少唤醒一个线程。
  int pthread_cond_broadcast( pthread_cond_t *cond );  // 唤醒全部线程。
  // 1 需要注意:要等条件状态改变以后,在使用这两个函数!!!
5 条件属性的初始化和类析构函数。
  int pthread_condattr_init( pthread_condattr_t *attr );
  int pthread_condattr_destroy( pthread_condattr_t *attr );
6 获取/设置 进程共享属性。
  int pthread_condattr_getpshared( const pthread_condattr_t *restrict attr, int *restrict pshared );
  int pthread_condattr_setpshared( pthread_condattr_t *attr, int *pshared );
7 获取/设置 时钟属性。
  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:屏障。

1 初始化,类析构函数(释放内存前使用)
  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设置后不会改变。
2 当前线程已完成,等待其他线程。
  int pthread_barrier_wait( pthread_barrier_t *barrier );  // 如未满足count数,则此线程进行休眠。
3 初始化 和 类析构函数。
  int pthread_barrierattr_init( pthread_barrierattr_t *attr );
  int pthread_barrierattr_destroy( pthread_barrierattr_t *attr );
4 获取/设置 进程共享属性。
  int pthread_barrierattr_getpshared( const pthread_barrierattr *restrict attr, int *restrict pshared );
  int pthread_barrierattr_setpshared( pthread_barrierattr *attr, int pshared );

三、

时间: 2024-11-10 13:01:07

linux学习笔记之线程同步机制的相关文章

APUE学习笔记——11 线程同步、互斥锁、自旋锁、条件变量

线程同步 同属于一个进程的不同线程是共享内存的,因而在执行过程中需要考虑数据的一致性. 假设:进程有一变量i=0,线程A执行i++,线程B执行i++,那么最终i的取值是多少呢?似乎一定是i=2:其实不然,如果没有考虑线程同步,i的取值可能是1.我们先考虑自加操作的过程:a,首先将内存中i的值copy到寄存器:b,对寄存器中i的copy进行自加:c,将寄存器中自加的结果返回到内存中.回到例子,如果线程A执行完abc三个步骤,线程B在执行者三个步骤,那么结果就应该为2.但是自加不是原子操作,假如执行

Linux下C的线程同步机制

C里提供了保证线程安全性的三种方法: (添加头文件#include<pthread.h>,pthread 库不是 Linux 系统默认的库,连接时需要使用静态库 libpthread.a, 在编译中要加 -lpthread参数) 互斥锁 通过锁的机制实现线程间的互斥,同一时刻只有一个线程可以锁定它,当一个锁被某个线程锁定的时候,如果有另外一个线程尝试锁定这个临界区(互斥体),则第二个线程会被阻塞,或者说被置于等待状态.只有当第一个线程释放了对临界区的锁定,第二个线程才能从阻塞状态恢复运行. i

linux学习笔记之线程

一.基础知识 1:基础知识. 1,线程需要的信息有:线程ID,寄存器,栈,调度优先级和策略,信号屏蔽字,errno变量和线程私有数据. 2,进程的所有信息对所有线程都是共享的. 3,是否支持有多线程有以下两种方式测试: 1)编译时确定:#ifdef _POSIX_THREADS 2)运行时确定:sysconf函数调用 _SC_THREADS 常用. 4,线程ID. 1)一个进程中,线程ID具有唯一性.线程ID依赖与进程后,才有意义. 2)线程ID表示类型:pthread_t类型 5,变量增量操作

Linux学习笔记(三)-Shell命令机制

切换命令行:ctrl+alt+f1-f6 切换到图形界面:ctrl+alt+f7 ls-list(win下的dir) 白色:普通文件 蓝色:目录文件 绿色:可执行文件 执行步骤: 输入ls 在相关目录下去找命令程序(path,环境变量:/etc/environment),whereis+命令:查找该命令的可执行文件的位置 基于shell的基本类库Bash 底层的交互 GNU,FSF,Bash,Coreutils 来自为知笔记(Wiz)

Linux程序设计学习笔记----多线程编程线程同步机制之互斥量(锁)与读写锁

互斥锁通信机制 基本原理 互斥锁以排他方式防止共享数据被并发访问,互斥锁是一个二元变量,状态为开(0)和关(1),将某个共享资源与某个互斥锁逻辑上绑定之后,对该资源的访问操作如下: (1)在访问该资源之前需要首先申请互斥锁,如果锁处于开状态,则申请得到锁并立即上锁(关),防止其他进程访问资源,如果锁处于关,则默认阻塞等待. (2)只有锁定该互斥锁的进程才能释放该互斥锁. 互斥量类型声明为pthread_mutex_t数据类型,在<bits/pthreadtypes.h>中有具体的定义. 互斥量

Linux System Programming 学习笔记(七) 线程

1. Threading is the creation and management of multiple units of execution within a single process 二进制文件是驻留在存储介质上,已被编译成操作系统可以使用,准备执行但没有正运行的休眠程序 进程是操作系统对 正在执行中的二进制文件的抽象:已加载的二进制.虚拟内存.内核资源 线程是进程内的执行单元 processes are running binaries, threads are the smal

操作系统学习笔记----进程/线程模型----Coursera课程笔记

操作系统学习笔记----进程/线程模型----Coursera课程笔记 进程/线程模型 0. 概述 0.1 进程模型 多道程序设计 进程的概念.进程控制块 进程状态及转换.进程队列 进程控制----进程创建.撤销.阻塞.唤醒.... 0.2 线程模型 为什么引入线程 线程的组成 线程机制的实现 用户级线程.核心级线程.混合方式 1. 进程的基本概念 1.1 多道程序设计 允许多个程序同时进入内存运行,目的是为了提高CPU系统效率 1.2 并发环境与并发程序 并发环境: 一段时间间隔内,单处理器上

【转】Python线程同步机制: Locks, RLocks, Semaphores, Conditions, Events和Queues

Python线程同步机制: Locks, RLocks, Semaphores, Conditions, Events和Queues | Comments 翻译自Laurent Luce的博客原文名称:Python threads synchronization: Locks, RLocks, Semaphores, Conditions, Events and Queues原文连接:http://www.laurentluce.com/posts/python-threads-synchron

Linux系统开发9 线程同步

[本文谢绝转载原文来自http://990487026.blog.51cto.com] <大纲> Linux系统编程8 线程同步 多线程共享资源,不加锁,同步互斥演示 多线程共享资源,加锁,同步互斥演示 读写锁:3个写线程,5个读线程,不加锁,并行处理 读写锁:3个写线程,5个读线程,加读写锁,串行处理 条件变量:生产消费者模型 信号量 进程间锁 文件锁: 习题 死锁,哲学家就餐 多线程共享资源,不加锁,同步互斥演示 [email protected]:~/linux_c/thread$ ca