同步
线程同步—协同步调,有先后的运行次序,保证数据一致性。
出现与时间有关的错误,需要使用同步机制:
- 数据共享
- 竞争
- 多个对象访问
锁不具有强制性,非“君子”的线程仍然可以访问。Linux中都是建议锁,不具有强制性
互斥量/互斥锁
初始化后初值为1 !!!
pthread_mutex_tpthread_mutex_init(&mutex,NULL);//mutex -> 1**restrict关键字限制不能通过除了本指针以外的其他变量或指针修改pthread_mutex_lock(&mutex);//deal......pthread_mutex_unlock(&mutex);pthread_mutex_destroy(&mutex);
访问共享数据前加锁,访问结束后立即解锁,使锁的粒度尽可能小
死锁
- 线程试图对同一互斥量加锁两次,加锁第二次阻塞,无限等待
- 两个数据,两把锁,两个进程;TI有A锁请求B锁,T2有B锁请求A锁;同时阻塞
解决方法:
获取所有需要的锁失败,主动放弃已有的锁
DEMO模拟实现死锁现象
读写锁
和互斥量类似,效率较高,写独占,读共享,写锁(抢占过程中)优先级高
一把锁具备三种状态:读锁 写锁 不加锁
pthread_rwlock_tpthread_rwlock_initpthread_rwlock_destroy//rdlock wrlock tryrdlock(非阻塞) trywrlock unlock
条件变量
条件变量本身不是锁,条件变量是描述一个条件,但是可以让进程阻塞,和互斥锁配合使用。
pthread_cond_initpthread_cond_destroypthread_cond_wait //阻塞等待一个条件变量//参数需要一把互斥锁pthread_cond_timedwait//阻塞设定时常pthread_cond_signal//唤醒一个阻塞在条件变量上的线程pthread_cond_broadcast//唤醒至少一个阻塞在条件变量上的线程
pthread_cond_wait
- 阻塞等待条件变量
- 释放已掌握的互斥锁
- 1,2为原子操作
- 等待唤醒,pthread_cond_wait返回时 解除阻塞 重新申请加锁
pthread_timed_wait
struct timespec* abs_time;//绝对时间 1970-01-01 00:00:00// s ns// 初始化用法time_t cur = time(NULL);struct timespec t;t.tv_sec = cur+1;//然后传参//timeval s ms
条件变量的优点
减小消费者的竞争,提高程序效率
生产者消费者条件变量模型
#include<stdio.h>#include<stdlib.h>#include<unistd.h>#include<pthread.h>#include<string.h>pthread_mutex_t mutex;pthread_cond_t cond;int product = 0;void* produce(void* arg){int i=50;while(i--){pthread_mutex_lock(&mutex);pthread_mutex_unlock(&mutex);printf("produce: %d\n",++product);pthread_cond_signal(&cond);sleep(3);}}void* consume(void* arg){int i=10;while(i--){pthread_mutex_lock(&mutex);while(product==0)//惊群效应pthread_cond_wait(&cond,&mutex);printf("consume: %d\n",--product);pthread_mutex_unlock(&mutex);sleep(2);}}int main(){pthread_mutex_init(&mutex,NULL);pthread_cond_init(&cond,NULL);pthread_t tid[6];for(int i=0;i<5;i++){pthread_create(&tid[i],NULL,consume,NULL);}pthread_create(&tid[5],NULL,produce,NULL);for(int i=0;i<6;i++)pthread_join(tid[i],NULL);pthread_mutex_destroy(&mutex);pthread_cond_destroy(&cond);return 0;}
信号量(互斥量升级版 多个线程)
线程进程通用
sem_t // 0~nsem_init //设置是否在进程间共享 --信号量初值 决定信号量的线程个数--sem_destroysem_trywaitsem_wait //信号量-- 0阻塞sem_timedwaitsem_post //信号量++
生产者消费者 信号量 模型
//两个信号量 产品数 剩余空间数
进程间同步方法
- 信号量
- 互斥量(修改属性为进程间共享)
pthread_mutexattr_initpthread_mutex_setpsharedPTHREAD_PROCESS_PRIVATEPTHREAD_PROCESS_SHARED//进程
- 文件锁(fcntl)
F_SETLK//设置文件锁 非阻塞F_SETLKW//设置文件锁 阻塞//加锁解锁宏相同 通过flock结构体控制F_GETLK//获取文件锁struct flock{l_type 读锁解锁写锁whence偏移位置 SEEK_SET CUR ENDstart起始偏移 从偏移位置开始len传0锁整个文件pid F_GETLKONLY}
多线程无法使用文件锁,可以使用读写锁
