智慧团建官方网站登录,工商注册核名查询系统官网,无锡网络公司排名,百中搜优化软件一、线程竞争基本概念 竞争与同步 同一个进程中的线程共享进程中的绝大多数资源#xff0c;当它们随意竞争时可能会导致资源被破坏、脏数据、不完整问题 通过一些手段让线程在竞争资源时相互协调、避免出现以上问题#xff0c;这就称为线程同步 原子操作#xff1a; 操作过程…一、线程竞争基本概念 竞争与同步 同一个进程中的线程共享进程中的绝大多数资源当它们随意竞争时可能会导致资源被破坏、脏数据、不完整问题 通过一些手段让线程在竞争资源时相互协调、避免出现以上问题这就称为线程同步 原子操作 操作过程中不能被打断的操作称为原子操作 临界资源、临界区、竞态条件 能够被多个进程访问但是又无法同时访问的资源称为临界资源 每个进程中访问临界资源的那段代码称为临界区能够被多个线程访问但是又无法同时访问的代码片段 多个线程在临界区内执行时由于线程的执行顺序具有随机性从而导致结果不确定称为发生了竞态条件 二、互斥量(互斥锁) man手册中没有全部的posix手册文档需要安装 sudo apt-get install manpages-posix-dev pthread_mutex_t 是一种数据类型用来定义互斥锁变 int pthread_mutex_init(pthread_mutex_t* mutex,const pthread_mutexattr_t * attr); 功能对互斥量进行初始化完成后锁处于开锁状态 mutex要初始化的互斥量 attr互斥量的属性设置一般默认给NULL即可 也可以在定义时通过PTHREAD_MUTEX_INITIALIZER初始化互斥量 pthread_mutex_t mutex PTHREAD_MUTEX_INITIALIZER; int pthread_mutex_lock(pthread_mutex_t *mutex); 功能对互斥量加锁成功则返回继续执行失败则阻塞休眠等待直到互斥量解锁并成功加锁才唤醒返回 int pthread_mutex_unlock(pthread_mutex_t *mutex); 功能对互斥量解锁对别人上锁的互斥量解锁失败返回EBUSY int pthread_mutex_trylock(pthread_mutex_t *mutex); 功能对互斥量尝试加锁成功返回0 失败返回EBUSY立即返回 int pthread_mutex_destroy(pthread_mutex_t *mutex); 功能销毁互斥量 三、读写锁 读写锁将线程访问共享数据时发出的请求分为两种 读请求只读取共享数据不修改 写请求存在修改共享数据的行为 1、当有多个线程同时发出读请求可以同时执行 2、当有多个线程同时发出写请求只能一个一个的执行 3、当发出读请求的线程正在执行时发出写请求的线程必须等待前面所有读请求线程执行完后才能执行 4、当发出写请求的线程正在执行时发出读请求的线程必须等待前面所有写请求线程执行完后才能执行 当读写锁被发出读请求的线程占用时称为读锁当读写锁被发出读请求的线程占用时称为写锁 1、当读写锁未被任何线程占用称为无锁发出读请求、写请求的线程都可以占用如果同时请求默认优先给读请求占用 2、当变成读锁(多个线程占用)时读请求的线程可以占用不会阻塞但是写请求的线程会阻塞等待读锁解锁 3、当变成写锁(单个线程占用)时读、写请求的线程都会阻塞等待写锁解锁 pthread_rwlock_init 初始化读写锁 pthread_rwlock_wrlock 写锁上锁 pthread_rwlock_rdlock 读锁上锁 pthread_rwlock_unlock 解锁 pthread_rwlock_destroy 销毁 四、自旋锁 在任意时刻最多只能有一个线程获取该锁 对于互斥量如果资源已经被占用申请者会进入休眠态 对于自旋锁则不会引起申请者休眠而是一直在申请处进入循环不停地查看自旋锁是否解锁直到解锁并加锁成功后才退出循环往下执行 一般情况下使用互斥量但是如果知道被锁住的代码执行时间很短(或者是主动让其变短)那么应该选择使用系统开销(运行态-休眠态)较少的自旋锁更合适因为运行态进入休眠态时需要切换内核态 有点耗时 五、信号量 与进程间通信XSI机制中的信号量原理相似线程之间使用的全局的计数器用于控制访问有限的共享数据的线程数 sem_t 是一种数据类型用于定义信号量变量 int sem_init(sem_t *sem, int pshared, unsigned int value); 功能初始化信号量 sem要初始化的信号量 pshared 0 只能在本进程中使用 非0 表示该信号量可以以共享内存的方式被多个进程使用Linux不支持 value信号量的初始值 int sem_wait(sem_t *sem); 功能对信号量减1如果信号量的值为0则阻塞等待 int sem_trywait(sem_t *sem); 功能对信号量尝试减1如果信号量的值为0则立即返回EAGAIN成功返回0 int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout); 功能对信号量减1如果值为0则等待一段时间超时还没能减则返回ETIMEDOUT int sem_post(sem_t *sem); 功能对信号量的值加1 int sem_destroy(sem_t *sem); 功能销毁信号量 六、死锁 1、什么是死锁 多个进程或线程相互等待对方的资源在得到新资源前不会释放自己的旧资源这样就形成了循环等待该现象称为死锁 2、产生死锁的四大必要条件 资源互斥资源只有两种状态可用和不可用资源不能被同时使用同一时刻只能被一个进程或线程使用 占用且请求已经得到资源的进程或线程会继续请求新的资源并且持续占用旧资源 资源不可剥夺当资源已经分配给进程或线程后不能被其他进程或线程强制性获取除非占用者主动释放 环路等待死锁发生时系统中必定有两个或以上的进程或线程的执行路线形成等待环路 注意一旦产生死锁基本无解现在的操作系统无法解决死锁因此只能防止死锁的产生 3、防止死锁产生的方法 破坏互斥条件 想办法让资源能够共享 缺点受到环境或资金的影响无法让资源共享 破坏占用且请求 采用静态预分配的方式进程或线程在运行前尝试一次性申请所有的资源在资源没有得到全部满足不投入运行 缺点可能会导致系统资源的昂费因为有些资源是很靠后才会使用但是已经提前分配占用导致其它不会产生死锁的进程或线程也无法使用 破坏资源不可剥夺 当一个进程或线程占用了不可被剥夺的资源并且请求新资源无法得到满足时那么就把全部占用的资源主动释放过一段时间后重新开始 缺点该策略实现难度高释放已经占用的资源会导致前一阶段的工作失效还要反复申请释放资源浪费资源、时间 破坏环路等待 给每个资源进行编号进程或线程都按照编号顺序来请求资源并且必须拿到前一个编号资源后才能去拿后一个 缺点资源的编号顺序要相对稳定否则在运行期间资源的增加或删减都会让该过程受极大的影响 4、如何判断死锁 1、画出资源分配图 2、简化资源分配图 3、使用死锁定理判断看有没有环路 七、条件变量 当某些设置的条件满足时可以让线程自己进入睡眠态也可以在另一些设置的条件满足时可以被其它线程唤醒需要配合互斥量使用 pthread_cond_t 是一种数据类型用于定义条件变量 int pthread_cond_init(pthread_cond_t *restrict cond,const pthread_condattr_t *restrict attr); 功能初始化条件变量也可以直接使用PTHREAD_COND_INITIALIZER在定义时初始化 pthread_cond_t cond PTHREAD_COND_INITIALIZER; int pthread_cond_destroy(pthread_cond_t *cond); 功能销毁条件变量 int pthread_cond_wait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex); 功能让当前线程睡入条件变量cond并主动解锁线程自己的互斥量mutex //拿到资源先上锁满足条件就睡眠并且解锁 int pthread_cond_signal(pthread_cond_t *cond); 功能唤醒因为cond睡眠的其中一个线程线程醒来前要确保能对原来的互斥量重新加锁 //醒来之后 要能够拿到资源并上锁 与睡眠前的状态保持一致 int pthread_cond_timedwait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex,const struct timespec *restrict abstime); 功能让当前线程睡入cond最多睡abstime时间超时也会返回 使用条件变量和互斥量可以实现 生产者和消费者模型 八、生产者与消费者模型 C/S模型 生产者生产数据的线程 消费者使用数据的线程 仓库临时存储数据的缓冲区(仓库解决生产、消费不匹配的问题) 可能产生的问题 生产快于消费仓库爆满撑死 消费快于生产仓库空虚饿死 利用条件变量来解决以上问题 当缓冲区满的时候生产者睡入条件变量(full)并通知消费者全部醒了(empty) 当缓冲区空的时候消费者睡入条件变量(empty)并通知生产者全部醒来(full)
应用利用生产者消费者模型构建 线程池
线程池的封装gitee