多线程编程<二>

时间:2022-04-28 19:43:22
一、线程同步 1.mutex互斥量      多个线程同时访问共享数据时有可能会冲突,这出现了和可重入性同样的问题。      例如,当两个线程都想把某个全局变量增加1这个操作在某平台需要三条指令:
    • 1.从内存读变量值到寄存器。
    • 寄存器加1。
    • 将寄存器的值写回内存。
     此时,如果线程1在执行加1操作时,因为突发原因切出去,而线程2继续,则会导致这个全局变量不能达到预想结果。 所以,对于多线程的程序,为了解决访问冲突,解决的办法是引入互斥锁。只有得到锁的线程可以完成‘读-修改-写’的操作,然后释放锁给其他线程。而没有获得锁的线程只能等待而不能访问共享的数据,这样“读-修改-写”的三部操作就组成了一个原子操作,要么执行完要么不执行,不会在执行中间被打断,也不会在其他处理器上并行做这个操作      Mutex用pthread_mutex_t类型的变量表示。其相关函数如下。
  • 初始化函数和销毁函数
多线程编程<二>
pthread_mutex_init函数对Mutex做初始化,参数attr设定Mutex属性,若attr为NULL,则表示缺省属性。     pthread_mutex_destroy可以销毁Mutex。     若Mutex是静态分配的(全局变量或static变量),可以用宏定义PTHREAD_MUTEX_INITALIZER来初始化,相当于pthread_mutex_init初始化并且attr参数为NULL返回值:成功返回0,失败返回错误号
  • Mutex的加锁和解锁
多线程编程<二>

 一个线程可以调用pthread_mutex_lock获得Mutex。如果这时另一个线程已经调用pthread_mutex_lock获得Mutex,则当前线程需要挂起等待,直到另一个线程调用pthread_mutex_unlock释放Mutex,当前线程被唤醒,才能获得该Mutex继续执行     若一个线程既想获得锁又不想挂起等待,可以调用pthread_mutex_trylock,如果Mutex已经被另一个线程获得,这个函数返回EBUSY而不会使线程挂起等待。返回值:成功返回0,失败返回错误号 多线程编程<二>
  • 互斥锁实现原理:
     用swap或者exchange指令,把寄存器和内部单元的数据交换,由于仅有一条命令,所以保证了原子性,即使是多处理器平台,访问内存的总周期也有先后,一个处理器上的交换指令执行时另一个处理器的交换指令只能等待总线周期
  • 死锁:
     ①如果一个线程先后两个调用lock,第二次调用时,由于锁已经被占用,该线程会挂起等待别的线程释放锁,但是锁正是被自己占用,该线程又被挂起等待,没有机会释放锁,这样就永远处于等待状态。     ②线程A获得了锁1,线程B获得锁2,这时线程A掉用函数试图获得锁2,结果需要挂起等待线程B释放锁2,这时线程B也调用lock试图获得锁1,结果需要挂起等待线程A释放锁1,于是A和B相互等待,永远处于挂起。     *写程序时避免同时获得多个锁,若一定要获得多个锁,那么应该所有线程按一定的先后顺序获得锁,以保障不出现死锁
2.条件变量     线程间同步时,若线程A需要等某个条件成立时才能继续往下执行,若这个条件不成立,则A阻塞等待,若线程B在执行的过程中使这个条件成立,则唤醒线程A继续等待这个条件的线程。     条件变量用pthread_cond_t 类型变量表示
  • 初始化和销毁
多线程编程<二>
返回值:成功返回0失败返回错误号     条件变量和锁和搭配使用的。

例子:单生产者单消费者模型一个线程不断从链表中头插数据,一个线程不停的取数据。1.必须保证放完才能拿,拿完才能放。生产者和消费者是互斥关系,还需要一定的顺序,同步。2.生产者之间互斥,消费之间是竞争关系3.交易场所只有一个,数据缓存(数组、链表等可以保持数据特性的结构)4.3种关系,两种角色,一个交易场所
多线程编程<二>
多线程编程<二>
多线程编程<二>
多线程编程<二>

3、Semaphore信号量     Mutex变量非0即1,可以看做一种资源的可用数量,初始化Mutex为1,表示有1个资源可用,加锁时获得该资源。Mutex减到0,表示不再有可用资源,解锁时释放该资源,Mutex重新加到1,表示又有了一个可用资源。     信号量和Mutex类似,表示可用资源的数量,和Mutex不同的是这个数量可以大于1。
  • 信号量的函数
semaphore变量的类型为sem_t①初始化    
多线程编程<二>
②等待     获得资源(相当于P操作),时semaphore值减1,如果调用wait值为0则挂起等待 多线程编程<二>
③释放资源(V操作)     使semphore值加1,同时唤醒挂起等待的进程 多线程编程<二>
④destroy 多线程编程<二>
 上面生产-消费模型是基于链表的,其空间动态分配,现在基于固定大小的环形队列重写程序。通过信号量同步,不用锁 注意: 环形生产消费模型:生产者不能超过消费者,会覆盖原有数据,消费者也不会超过生产者,会读到空数据 判空方法:1.加计数器                   2.预留一个空间 对于生产者:只有当不满的的时候才可以生产,看重空间资源(space) 对于消费者:只有当有数据才读取,看重数据资源(data) 多线程编程<二> 多线程编程<二>
多线程编程<二>