线程同步=互斥锁+条件变量+信号量+文件锁(文件记录锁和文件锁) 死锁

在这里插入图片描述
线程的最大特点是资源的共享性,但资源共享中的同步问题是多线程编程的难点。

进程间同步方式:
①事件(Event) 【进程&线程间同步–内核对象】
②互斥量【进程&线程间同步–内核对象】可以命名→可以跨进程
③信号量(Semaphore)【进程&线程间同步–内核对象】–有名信号量
  比如socket套接字,HTTP限制用户访问数量
  信号量机制功能强大,但使用时对信号量的操作分散,而且难以控制,读写和维护都很困难。
  优:PV操作能够实现对临界区的管理要求;实现简单;允许使用它的代码休眠,持有锁的时间可相对较长。
  缺:信号量机制必须有公共内存,不能用于分布式操作系统,这是它最大的弱点。信号量机制功能强大,但使用时对信号量的操作分散,而且难以控制,读写和维护都很困难。加重了程序员的编码负担;核心操作P-V分散在各用户程序的代码中,不易控制和管理;一旦错误,后果严重,且不易发现和纠正。
  
④管程:针对信号量,又提出了一种集中式同步进程——管程
  将共享变量和对它们的操作集中在一个模块中,操作系统或并发程序就由这样的模块构成。这样模块之间联系清晰,便于维护和修改,易于保证正确性。
  缺:如果一个分布式系统具有多个CPU,并且每个CPU拥有自己的私有内存,它们通过一个局域网相连,那么这些原语将失效。而管程在少数几种编程语言之外又无法使用,并且,这些原语均未提供机器间的信息交换方法。
  
⑤自旋锁:
  调用者一直循环在那里看是否该自旋锁的保持着已经释放了锁,自旋锁是一种比较低级的保护数据结构和代码片段的原始方式。–【低开销,安全高效】
  导致问题:→(1)死锁 (2)过多地占用CPU资源

线程同步:
1.内核对象:
  ①事件(Event) 【进程&线程间同步–内核对象】  
  ②互斥量【进程&线程间同步–内核对象】
    有名互斥量→可跨进程&用名字打开
  ③信号量【进程&线程间同步–内核对象】–无名信号量
2.进程对象:
  ④文件锁(文件记录锁和文件锁):进程生存期资源【进程终止→文件锁被释放】
  ⑤条件变量【存放在进程地址空间内—进程对象-不能用于进程】
  ⑥临界区(Critical Section)【仅线程间,不能跨进程–用户方式的同步】
    →速度快,实现简单,相比互斥量而言速度更快且消耗资源少
  ⑦信号【属于异步通知吧,用于同步机制】
其中后两者需要依赖于共享内存才能用于进程间同步,因此只有文件锁是进程生存期的资源,其他的都属于内核生存期资源。

线程同步(本质是有序操作)

当有一个线程在对内存进行操作时,其他线程都不可以对这个内存地址进行操作,只能等,直到该线程完成操作

1、互斥锁mutex

类似临界区,但更复杂,互斥对象只有一个,只有拥有互斥对象的线程才具有访问资源的权限。

缺点:
1、跨越进程使用👉可以命名且创建互斥量需要的资源更多(跨进程的互斥量一旦被创建,就可以通过名字打开它)
//若仅仅是用于进程内,则相较于互斥量,临界区具有速度快,占用资源少的优势

2、通过互斥量可以指定资源被独占的方式使用
3、访问上限为1(临界区也是1,而信号量为1~若干)

在Linux操作系统中,用户层面上编程使用的所有锁都是建议锁,不具有强制性,因此访问共享数据的所有线程(进程)都应该先加锁才能访问。

  互斥量提供了对共享资源的保护访问,当一个线程使用互斥量锁定某个资源后,其他线程对该资源的访问都会被阻塞。 用于保护【临界区】(共享资源),以保证在任何时刻只有一个线程能够访问共享的资源。 互斥量类型声明为pthread_mutex_t数据类型。

注意:man 3 pthread_mutex_init时提示找不到函数,说明你没有安装pthread相关的man手册。安装方法:1、虚拟机上网;2、sudoapt-get install manpages-posix-dev

pthread_mutex_t 互斥锁类型//struct	近似为int
pthread_mutex_t mutex; 变量mutex(可用资源数量)只有两种取值1(空闲,可上锁)、0(已被占用)

1、互斥锁函数

12种初始化
	1、静态初始化://定义在全局,或加static关键字修饰
				pthead_mutex_t muetx = PTHREAD_MUTEX_INITIALIZER;//宏结构常量赋值给互斥锁(结构体)
	2、动态初始化:局部变量必须采用动态初始化:pthread_mutex_init(&mutex, NULL)#include <bits/pthreadtypes.h>
	int pthread_mutex_init(	pthread_mutex_t *mutex,
 		 					const pthread_mutexattr_t *attr); //互斥量属性,通常用NULL表默认属性【快速互斥锁】

2、销毁
int pthread_mutex_destroy(pthread_mutex_t *mutex);

32种上锁方式
	3.1、阻塞式上锁,若已被占据则阻塞等待
		int pthread_mutex_lock(pthread_mutex_t *mutex);
	3.2、非阻塞,若已被占据则立即返回BUSY
		int pthread_mutex_trylock(pthread_mutex_t *mutex);

4、解锁:	mutex++(或+1------归还使用权,并唤醒阻塞等待使用该资源的线程(有多个时,优先级决定唤醒谁)
int pthread_mutex_unlock(pthread_mutex_t *mutex);

5、销毁
int pthread_mutex_destroy(pthread_mutex_t *mutex)
销毁一个互斥锁即意味着释放它所占用的资源,且要求锁当前处于开放状态。
由于在Linux中,互斥锁并不占用任何资源,
因此LinuxThreads中的 pthread_mutex_destroy()除了检查锁状态以外(锁定状态则返回EBUSY)没有其他动作。

2、互斥锁属性

在创建互斥锁时指定属性
在LinuxThreads实现中仅有一个锁类型属性,不同的锁类型在试图对一个已经被锁定的互斥锁加锁时表现不同。当前(glibc2.2.3,linuxthreads0.9)有四个值可供选择:

1、PTHREAD_MUTEX_TIMED_NP 缺省(普通)锁,当一个线程加锁以后,其余请求锁的线程将形成一个等待队列,并在解锁后按优先级获得锁。这种锁策略保证了资源分配的公平性。
2、PTHREAD_MUTEX_RECURSIVE_NP,嵌套锁,允许同一个线程对同一个锁成功获得多次,并通过多次unlock解锁。如果是不同线程请求,则在加锁线程解锁时重新竞争。
3、PTHREAD_MUTEX_ERRORCHECK_NP,检错锁,如果同一个线程请求同一个锁,则返回EDEADLK,否则与PTHREAD_MUTEX_TIMED_NP类型动作相同。这样保证当不允许多次加锁时不出现最简单情况下的死锁。
4、PTHREAD_MUTEX_ADAPTIVE_NP,适应锁,动作最简单的锁类型,仅等待解锁后重新竞争。

对于普通锁和适应锁类型,解锁者可以是同进程内任何线程;而检错锁则必须由加锁者解锁才有效,否则返回EPERM;对于嵌套锁,文档和实现要求必须由加锁者解锁,但实验结果表明并没有这种限制,这个不同目前还没有得到解释。

2、条件变量cond:协调线程的执行顺序

从微观上来讲,线程同步要同时做到:
  ①保证线程互斥【互斥锁、信号量】
  ②保证线程的执行顺序【条件变量】
  
条件变量协调线程的执行顺序,从而保证线程 安全,有顺序的访问共享数据。
   通常与互斥锁配合使用,需要注意的是条件变量本身不是锁,而是给多线程提供一个会合的场所。

条件变量是利用线程间共享的全局变量进行同步的一种机制,主要包括两个动作:一个线程"因条件不成立"而挂起;另一个线程使"条件成立"(给出条件成立信号)。为了防止竞争,条件变量的使用总是和一个互斥锁结合在一起。

条件变量和互斥量
   条件变量并不是锁,但是可以通过调用条件变量相关API函数来造成线程阻塞,唤醒等,通常配合互斥量使用,很多操作并不是直接针对互斥量的,而是通过条件变量来影响互斥量。

条件变量允许线程阻塞等待特定条件发生,当条件不满足时,则调用条件变量的等待相关函数,让线程进入阻塞状态并等待条件发生改变,一旦某个线程满足条件就调用条件变量的通知相关函数,可通知唤醒一个或多个阻塞的线程。

条件变量如何实现阻塞线程:
cond本质上是一个等待队列,会把所有阻塞等待的线程放置在等待队列(被通知并满足条件时线程会离开等待队列),而互斥量用来保护等待队列,所以条件变量通常和互斥锁一起使用。

与条件变量结合使用时的互斥锁:
当有多个阻塞线程被广播唤醒时,通过互斥锁确保只有一个线程能够执行

2.1、条件变量的使用及函数

12种创建(和互斥锁类似)
	1.1、静态创建	pthread_cond_t cond = PTHREAD_COND_INITIALIZER;   /用宏创建
	1.2、动态创建	int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t  *cond_attr); 
	//尽管POSIX标准中为条件变量定义了属性&#x
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值