《APUE》学习记录之———多线程之间的同步

    一个进程的所有线程都可以访问该进程的组成部分(文件描述符,内存等);

    每个线程都包含有表示执行环境所需的信息,其中包括进程中标识线程的线程ID,一组寄存器值,栈,调度优先级,信号屏蔽字,errno变量以及线程私有数据,一个进程所有信息对该进程的线程都是共享的,包括可执行程序的代码(正文段),程序的全局内存和堆内存,栈以及文件描述符;

线程同步:

    线程同步的必要性:当多个控制线程共享相同的内存时,需要确保每个线程看到一致的数据视图。当一个线程可以修改的变量也可以被其他线程读取或修改时,就需要确保它们在访问变量的存储内容时不会访问到无效的值(情况一:线程A读取变量然后赋予新的值,需要两个存储器周期,如果线程B在其中读取变量的值,情况二:两个线程同时修改一个变量,修改需要两个内存周期,先读入修改,接着写入变量,两个线程两步交错在一起,就会出现看起来只修改一次的情况);

同步机制:

   方法一:对数据加锁

    线程同步的关键:使用锁来保护数据,确保同一时间内只有一个线程访问数据;

    锁的类型:互斥量,读写锁,带有超时的读写锁,自旋锁

    互斥量:

    在访问共享资源琪前对互斥量进行加锁,在访问完成后释放互斥量,对互斥量进行加锁后,任何其他试图再次对互斥量加锁的线程都会被阻塞(可以使用pthread_mutex_trylock尝试加锁,不会导致线程阻塞),直到当前线程释放该互斥锁;如果有一个以上的线程阻塞,那么所有该锁上的阻塞线程后悔变为可运行状态,第一个变为运行的线程就可以对互斥量加锁,而其他线程则再次等待;(单次一个线程向前

    读写锁(shared-exclusive lock):

    读写锁可以有三种状态:读模式下加锁状态,写模式下加锁状态,不加锁状态;、

    当读写锁是写加锁状态,在解锁前,所有试图对这个锁加锁的线程都会被阻塞(类似互斥量);

    当读写锁是在读加锁状态时,所有以读模式加锁的线程的都可以获得访问权,但是任何以写模式加锁的线程都是阻塞;

    读写锁适用于对数据读的次数远大于写的情况;(读取线程向前,写线程等待

    带有超时的读写锁

    行为和“不计时”版本基本一致,在调用接口时,传递一个timespec数据结构,指定线程应该停止阻塞的时间,如果不能获取锁且超时到期,那么就会返回ETIMEOUT错误(停止阻塞);(读取线程向前,写线程等待指定时间

    自旋锁

    自旋锁与互斥量类似,但是不是通过休眠的方式使进程阻塞,而是在获取锁前一直处于忙等(自旋)状态,

    自旋锁适用于:锁持有时间短,而且线程不希望在重新调度上花费太多成本;(单次一个线程向前

    (加锁的情况下)避免出现死锁:

    1. 线程试图对同一个互斥量加锁两次

    2.两个线程都在互相请求另外一个线程拥有的资源(解决办法:仔细控制加锁的顺序或试用非阻塞的尝试加锁)

    方式二:条件变量

    条件变量给多个线程提供一个会合的场所,条件变量与互斥量一起使用时,运行线程以无竞争的方式等待某个特定的条件发生;

    条件本身是受到互斥量保护的,线程在改变条件之前必须先锁住互斥量,其他线程在获得互斥量之前不会察觉到改变,因为互斥量必须在锁定之后才能计算条件;

int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);// 等待条件为真,如果给定的时间内条件不能满足,返回一个错误码的变量

    传递给pthread的互斥量对条件进行保护,调用者把锁住的互斥量传给函数,函数然后自动把调用线程放到等待的线程列表中,对互斥量进行解锁(关闭了线程进入休眠等待条件改变和条件检查这两个操作之间的时间通道,不会错过条件的改变),pthread_cond_wait返回时,互斥量再次被锁住;(函数解锁(加入等待队列完成)然后再(唤醒之后)加锁(唤醒之后获取资源访问权)

pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
//线程一:
pthread_mutex_lock(&mut);
while (x <= y) {
   pthread_cond_wait(&cond, &mut);
}
//conditon already happen, do something
pthread_mutex_unlock(&mut);
//线程二:
pthread_mutex_lock(&mut);
x = y + 1;
if (x > y) pthread_cond_broadcast(&cond);
pthread_mutex_unlock(&mut);

    优点:减少主动访问临界区的情况(减少获取锁),而是反过来当条件发生时(被通知),再来访问;(单个线程等待被通知然后前进

    方式三:屏障(barrier)

    屏障(barrier)协调多个线程并行工作的同步机制,屏障允许每个线程等待,直到所有合作线程都达到某一个点,然后从该点继续执行;

    调用pthread_barrier_wait的线程在屏障计数(初始化时设定),未满足条件时,会进入休眠状态,如果最后一个线程调用pthread_barrier_wait,满足了屏障计数,所有的线程都被唤醒;(设立“终点线”,每个线程等待最后一个线程到达,然后再前进

你可能感兴趣的:(学习笔记)