概述
文章内容
- 1. 信号量
- 2. 互斥量
- 3. 条件变量
- 4. 读写锁
- 5. C++线程编程
1. 信号量
为了使总进程和子线程两者之间可以有序的打印,对上一篇文章末尾的程序添加信号量
用同一个数p,主进程p从3开始递增5次,线程p从3开始递减10次
#include <pthread.h>
#include <unistd.h>
#include <iostream>
#include <semaphore.h>
using namespace std;
sem_t sem; // 全局变量
void* handle(void* p){
int* pn = (int*)p;
for(int i=0;i<10;++i){
sleep(1);
sem_wait(&sem); // 上锁
cout << pthread_self() << ":" << --*pn << endl;
sem_post(&sem); // 解锁
}
delete pn;
return NULL;
}
pair<pthread_t,int*> test(){
int* p = new int(3);
pthread_t tid;
pthread_create(&tid,NULL,handle,p);
return {tid,p};
}
int main(){
sem_init(&sem,0,1); // 信号量创建
cout << getpid() << endl;
cout << pthread_self() << endl;
auto [tid,p] = test(); // c++17
int n = 5;
for(int i=0;i<5;++i){
sleep(1);
sem_wait(&sem); // 上锁
cout << pthread_self() << ":" << ++*p << endl;
sem_post(&sem); // 解锁
}
pthread_join(tid,NULL);
sem_destroy(&sem); // 信号量销毁
return 0;
}
结果为:
[root@foundation1 C++7.13]# g++ thread4.cpp -pthread -std=c++17
[root@foundation1 C++7.13]# ./a.out
11460
139913218471744
139913200518912:2
139913218471744:3
139913200518912:2
139913218471744:3
139913200518912:2
139913218471744:3
139913200518912:2
139913218471744:3
139913200518912:2
139913218471744:3
139913200518912:2
139913200518912:1
139913200518912:0
139913200518912:-1
139913200518912:-2
并发过程中在2和3僵持,等待阶段开始递减
2. 互斥量
分类:
分类 | 实现 | 特点 |
---|---|---|
静态分配互斥量 | pthread_mutex_t mutex= PTHREAD_MUTEX_INITIALIZER; | 简单 |
动态分配互斥量 | pthread_mutex_init(&mutex, NULL); pthread_mutex_destroy(&mutex); | 可以设置更多的选项 |
操作:
操作 | 函数 |
---|---|
加锁 | int pthread_mutex_lock(pthread_t *mutex) |
尝试加锁 | int pthread_mutex_trylock(pthread_t *mutex) |
解锁 | int pthread_mutex_unlock(pthread_t *mutex) |
示例:
使用静态分配互斥量 pthread_mutex_t 互斥锁
加锁 pthread_mutex_lock(&互斥锁)
解锁 pthread_mutex_unlock(&互斥锁)
使用动态分配互斥量 pthread_mutex_init(&互斥锁, NULL);
动态分配销毁 pthread_mutex_destroy(&互斥锁);
(也可以不加)
互斥量,也叫互斥锁,比信号量简单一些
把之前的所换成互拆锁
#include <pthread.h>
#include <unistd.h>
#include <iostream>
#include <semaphore.h>
using namespace std;
// sem_t sem;
pthread_mutex_t mutex; // = PTHREAD_MUTEX_INITIALIZER;
void* handle(void* p){
int* pn = (int*)p;
for(int i=0;i<10;++i){
sleep(1);
// sem_wait(&sem);
pthread_mutex_lock(&mutex); // 上互斥锁
cout << pthread_self() << ":" << --*pn << endl;
pthread_mutex_unlock(&mutex); // 解互斥锁
//sem_post(&sem);
}
delete pn;
return NULL;
}
pair<pthread_t,int*> test(){
int* p = new int(3);
pthread_t tid;
pthread_create(&tid,NULL,handle,p);
return {tid,p};
}
int main(){
pthread_mutex_init(&mutex,NULL);
// sem_init(&sem,0,1);
cout << getpid() << endl;
cout << pthread_self() << endl;
auto [tid,p] = test(); // c++17
int n = 0;
// pthread_detach(tid);
for(int i=0;i<5;++i){
sleep(1);
// sem_wait(&sem);
pthread_mutex_lock(&mutex); // 上互斥锁
cout << pthread_self() << ":" << ++*p << endl;
pthread_mutex_unlock(&mutex); // 解互斥锁
// sem_post(&sem);
}
pthread_join(tid,NULL);
pthread_mutex_destroy(&mutex);
return 0;
}
结果为:
[root@foundation1 C++7.13]# g++ thread5.cpp -pthread -std=c++17
[root@foundation1 C++7.13]# ./a.out
3817
140049311688512
140049293735680:2
140049311688512:3
140049293735680:2
140049311688512:3
140049293735680:2
140049311688512:3
140049293735680:2
140049311688512:3
140049293735680:2
140049311688512:3
140049293735680:2
140049293735680:1
140049293735680:0
140049293735680:-1
140049293735680:-2
信号量和互斥量的区别:
区别 | 信号量 | 互斥量 |
---|---|---|
使用对象 | 线程和进程 | 线程 |
量值 | 非负整数 | 0或1 |
操作 | PV操作可由不同线程完成 | 加锁和解锁必须由同一线程使用 |
应用 | 用于线程的同步 | 用于线程的互斥 |
互斥:主要关注于资源访问的唯一性和排他性。
同步:主要关注于操作的顺序,同步以互斥为前提。
3. 条件变量
条件变量: 线程挂起直到共享数据的某些条件得到满足(完成条件后再执行线程)
分类:
分类 | 实现 | 特点 |
---|---|---|
静态分配条件变量 | pthread_cond_t cond = PTHREAD_COND_INITIALIZER; | 简单 |
动态分配条件变量 | pthread_cond_init(&cond, NULL);pthread_cond_destroy(&cond); | 可以设置更多的选项 |
操作:
操作 | 函数 |
---|---|
条件等待 | int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) |
计时等待 | int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime) |
单个激活 | int pthread_cond_signal(pthread_cond_t *cond) |
全部激活 | int pthread_cond_broadcast(pthread_cond_t *cond) |
示例:
每到5秒计算一下和
#include <iostream>
#include <pthread.h>
#include <vector>
#include <numeric>
#include <unistd.h> // sleep
using namespace std;
// 子线程
void* sum(void* data){
vector<int>& p = *(vector<int>*)data;
while(true){
sleep(5);
cout << "sum:" << accumulate(p.begin(),p.end(),0) << endl; // p中所有数的和
}
}
int main(){
vector<int> data;
pthread_t tid;
pthread_create(&tid,NULL,sum,&data); // 创建线程
// 主线程
int n;
while(cin >> n){
data.push_back(n);
}
pthread_join(tid,NULL); // 合并线程
}
结果为:
[root@foundation1 C++7.13]# g++ cond.cpp -pthread
[root@foundation1 C++7.13]# ./a.out
sum:0
1
2
sum:3
sum:3
3
4
5
sum:15
sum:15
^C
等到输入五个后再求和,每次清零
静态分配条件变量 pthread_cond_t 条件变量 = PTHREAD_COND_INITIALIZER;
条件等待 pthread_cond_wait(&条件变量, &互斥量)
这里为什么要写互斥锁?
因为这条代码要控制这个互斥锁,要先解锁让别的线程使用,等满足条件后,会抢锁自己用
单个激活 pthread_cond_signal(&条件变量)
#include <iostream>
#include <pthread.h>
#include <vector>
#include <numeric>
#include <unistd.h>
using namespace std;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; // 静态互斥量
pthread_cond_t cond = PTHREAD_COND_INITIALIZER; // 静态条件变量
void* sum(void* data){
vector<int>& p = *(vector<int>*)data;
while(true){
pthread_mutex_lock(&mutex); // 互斥量上锁
if(p.size()<5) pthread_cond_wait(&cond,&mutex); // 子线程如果在这个条件下,等待
cout << "sum:" << accumulate(p.begin(),p.end(),0) << endl;
p.clear();
pthread_mutex_unlock(&mutex); // 互斥量解锁
}
}
int main(){
vector<int> data;
pthread_t tid;
pthread_create(&tid,NULL,sum,&data);
int n;
while(cin >> n){
pthread_mutex_lock(&mutex); // 互斥量上锁
data.push_back(n);
if(data.size()>=5) pthread_cond_signal(&cond); // 主线程如果在这个条件下,发送
pthread_mutex_unlock(&mutex); // 互斥量解锁
}
pthread_join(tid,NULL);
}
结果为:
[root@foundation1 C++7.13]# g++ cond2.cpp -pthread
[root@foundation1 C++7.13]# ./a.out
1
2
3
4
5
sum:15
2
1
2
1
2
sum:8
^C
使用动态分配的方式
动态分配条件变量 pthread_cond_init(&条件变量, NULL);
动态分配销毁pthread_cond_destroy(&cond);
定义一个类,把变量汇总
#include <iostream>
#include <pthread.h>
#include <vector>
#include <numeric>
#include <unistd.h>
using namespace std;
struct Data{
vector<int>& data;
pthread_mutex_t& mutex;
pthread_cond_t& cond;
};
void* sum(void* data){
vector<int>& p = ((Data*)data)->data;
pthread_mutex_t& mutex = ((Data*)data)->mutex;
pthread_cond_t& cond = ((Data*)data)->cond;
while(true){
pthread_mutex_lock(&mutex);
if(p.size()<5) pthread_cond_wait(&cond,&mutex); // 子线程不满足条件,等
cout << "sum:" << accumulate(p.begin(),p.end(),0) << endl;
p.clear();
pthread_mutex_unlock(&mutex);
}
}
int main(){
pthread_mutex_t mutex; // = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond; // = PTHREAD_COND_INITIALIZER;
pthread_mutex_init(&mutex,NULL);
pthread_cond_init(&cond,NULL);
vector<int> data;
pthread_t tid;
Data d = {data,mutex,cond};
pthread_create(&tid,NULL,sum,&d);
int n;
while(cin >> n){
pthread_mutex_lock(&mutex);
data.push_back(n);
if(data.size()>=5) pthread_cond_signal(&cond); // 主线程满足条件,发送
pthread_mutex_unlock(&mutex);
}
pthread_join(tid,NULL);
pthread_mutex_destroy(&mutex);
pthread_cond_destroy(&cond);
}
结果是一样的
4. 读写锁
有时几个读取过程可以共同读,这样可以提高工作效率,读写锁可以分为读锁和写锁
读锁:读的过程中其他读也可以进行读操作
写锁:写的过程中不能进行其他操作
分类:
分类 | 实现 | 特点 |
---|---|---|
静态分配读写锁 | pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER | 简单 |
动态分配读写锁 | pthread_rwlock_init(&rwlock, NULL);pthread_rwlock_destroy(&rwlock); | 可以设置更多的选项 |
操作:
操作 | 函数 |
---|---|
读取锁 | int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock); |
写入锁 | int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock); |
解锁 | int pthread_rwlock_unlock(pthread_rwlock_t *rwlock) |
5. C++线程编程
之前都是属于Linux线程编程,我们使用C++线程编程,实现之前的操作,更加简单
#include <thread>
#include <iostream>
#include <mutex>
using namespace std;
int main(){
mutex m; // 定义互斥锁
// 子线程
thread t( [&m](){ // 引进变量
for(int i=0;i<5;++i){
this_thread::sleep_for(1s); // 停1秒
m.lock(); // 加锁
cout << this_thread::get_id() << ":" << i << endl;
m.unlock(); // 解锁
}
} );
// 主线程
for(int i=0;i<5;++i){
this_thread::sleep_for(1s);
m.lock(); // 加锁
cout << this_thread::get_id() << ":" << i << endl;
m.unlock(); // 解锁
}
t.join(); // 线程合并,等一下
}
结果为:
[root@foundation1 C++7.13]# g++ xian.cpp -pthread
[root@foundation1 C++7.13]# ./a.out
140127224375104:0
140127206422272:0
140127224375104:1
140127206422272:1
140127224375104:2
140127206422272:2
140127224375104:3
140127206422272:3
140127206422272:4
140127224375104:4
等到输入五个后再求和,每次清零
面对c++线程编程的条件变量 cond.wait 时,需要在前面定义唯一锁:unique_lock<mutex> lock(m);
对于条件变量 cond.notify_one 时可定义为 lock_guard<mutex> lock(m);
两者都有加锁和解锁的功能
#include <thread>
#include <iostream>
#include <mutex>
#include <numeric>
#include <vector>
#include <condition_variable>
using namespace std;
int main(){
mutex m;
condition_variable cond;
vector<int> vec;
// 子线程
thread t( [&](){
while(true){
unique_lock<mutex> lock(m); // 定义唯一锁
// m.lock();
if(vec.size() < 5) cond.wait(lock); // 条件变量,等
cout << "sum:" << accumulate(vec.begin(),vec.end(),0) << endl;
vec.clear();
// m.unlock();
}
} );
// 主线程
int n;
while(cin >> n){
lock_guard<mutex> lock(m);
// m.lock();
vec.push_back(n);
if(vec.size() >= 5) cond.notify_one(); // 条件变量,发
// m.unlock();
}
t.join();
}
最后
以上就是要减肥苗条为你收集整理的Linux系统编程:多线程同步1. 信号量2. 互斥量3. 条件变量4. 读写锁5. C++线程编程的全部内容,希望文章能够帮你解决Linux系统编程:多线程同步1. 信号量2. 互斥量3. 条件变量4. 读写锁5. C++线程编程所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复