深入学习c++--多线程编程(二)【当线程间需要共享非const资源】
1. 遇到的问题
#include <iostream>
#include <thread>
#include <chrono>
#include <future>
#include <cmath>
#include <vector>
#include <cstdlib>
using namespace std; class Counter
{
public:
void addCount() {
m_count++;
}
int count() const { return m_count; }
Counter() : m_count() { }
private:
int m_count;
}; int work(int a)
{
return a + a;
} template<class Iter>
void realWork(Counter& c, double &totalValue, Iter b, Iter e)
{
for (; b != e; ++b)
{
totalValue += work(*b);
c.addCount();
}
} int main()
{
unsigned n = std::thread::hardware_concurrency();
cout << n << " concurrent threads are support.\n"; vector<int> vec;
double totalValue = ;
for (int i = ; i < ; i++)
{
vec.push_back(rand() % );
}
Counter counter;
realWork(counter, totalValue, vec.begin(), vec.end());
cout << "total times: " << counter.count() << " " << totalValue << endl; totalValue = ;
Counter counter2;
auto iter = vec.begin() + (vec.size() / );
auto iter2 = vec.begin() + (vec.size() / * );
thread b([&counter2, &totalValue, iter, iter2](){
realWork(counter2, totalValue, iter, iter2);
});
auto end = vec.end();
thread c([&counter2, &totalValue, iter2, end](){
realWork(counter2, totalValue, iter2, end);
}); realWork(counter2, totalValue, vec.begin(), iter); b.join();
c.join();
cout << "total times use multithread: " << counter2.count() << " " << totalValue << endl; return ;
}
计算结果不一致!三个线程共享一份资源,有的加了有的没加。
2. 解决
2.1 法一:不共享变量
#include <iostream>
#include <thread>
#include <chrono>
#include <future>
#include <cmath>
#include <vector>
#include <cstdlib>
using namespace std; class Counter
{
public:
void addCount() {
m_count++;
}
int count() const { return m_count; }
Counter() : m_count() { }
private:
int m_count;
}; int work(int a)
{
return a + a;
} template<class Iter>
void realWork(Counter& c, double &totalValue, Iter b, Iter e)
{
for (; b != e; ++b)
{
totalValue += work(*b);
c.addCount();
}
} int main()
{
unsigned n = std::thread::hardware_concurrency();
cout << n << " concurrent threads are support.\n"; vector<int> vec;
double totalValue = ;
for (int i = ; i < ; i++)
{
vec.push_back(rand() % );
}
Counter counter;
realWork(counter, totalValue, vec.begin(), vec.end());
cout << "total times: " << counter.count() << " " << totalValue << endl; totalValue = ;
Counter counter2;
auto iter = vec.begin() + (vec.size() / );
auto iter2 = vec.begin() + (vec.size() / * );
double totalC = ;
thread b([&counter2, &totalValue, iter, iter2](){
realWork(counter2, totalValue, iter, iter2);
});
auto end = vec.end();
thread c([&counter2, &totalC, iter2, end](){
realWork(counter2, totalC, iter2, end);
}); double totalD = ;
realWork(counter2, totalD, vec.begin(), iter); b.join();
c.join();
cout << "total times use multithread: " << counter2.count() << " " << totalValue+totalC+totalD << endl; return ;
}
2.2 法二:原子操作变量类型(复杂,适合简单应用)
b,c 线程共享了变量 counter2, 没有共享变量 totalValue,所以totalValue一样,counter2.count()不一样
count++: 写入寄存器,寄存器+1,写入内存
average()函数功能是如果Counter2不等于10000000,程序就不退出,如运行截图,由于共享变量counter2, 导致counter2总是无法等于10000000
#include <iostream>
#include <thread>
#include <chrono>
#include <future>
#include <cmath>
#include <vector>
#include <cstdlib>
#include <string>
using namespace std; class Counter
{
public:
void addCount() {
m_count++;
}
int count() const { return m_count; }
Counter() : m_count() { }
private:
int m_count;
}; int work(int a)
{
return a + a;
} template<class Iter>
void realWork(Counter& c, double &totalValue, Iter b, Iter e)
{
for (; b != e; ++b)
{
totalValue += work(*b);
c.addCount();
}
} void printAll(int a, int b, int c)
{
cout << a << " " << b << " " << c << endl;
} void add(int a, int b, int& c)
{
c = a + b;
} void printString(const string& info, const string& info2)
{
cout << "hello " << info << " " << info2 << endl;
} void testThreadInit()
{
int a = ;
int b = ;
int c = ;
thread t([=](){
printAll(a, b, c);
});
t.join(); thread t2(printAll, a, b, c);
t2.join(); thread t3([=, &c](){
add(a, b, c);
});
t3.join();
cout << "after add: " << c << endl; // c是引用, 必须用 ref(c)
c = ;
thread t4(add, a, b, std::ref(c));
t4.join();
cout << "after add: " << c << endl; string abc("abc");
string def("def"); thread t5([&](){
printString(abc, def);
});
t5.join(); // 效率比引用低
thread t6(printString, abc, def);
t6.join(); // cref: 常引用
thread t7(printString, cref(abc), cref(def));
t7.join(); } bool average(Counter& c, int maxCount)
{
auto cnt = c.count();
if (cnt == maxCount) {
cout << " ok finished \n";
return true;
}
return false;
} int main()
{
testThreadInit(); // (1) 如果没有必要的话,线程间不要共享资源
unsigned n = std::thread::hardware_concurrency();
cout << n << " concurrent threads are support.\n"; vector<int> vec;
double totalValue = ;
for (int i = ; i < ; i++)
{
vec.push_back(rand() % );
}
Counter counter;
realWork(counter, totalValue, vec.begin(), vec.end());
cout << "total times: " << counter.count() << " " << totalValue << endl; totalValue = ;
Counter counter2;
thread printCount([&counter2](){
while (!average(counter2, )) {
}
});
auto iter = vec.begin() + (vec.size() / );
auto iter2 = vec.begin() + (vec.size() / * );
double totalC = ;
//b,c 线程共享了变量 counter2, 没有共享变量 totalValue,所以totalValue一样,counter2.count()不一样
thread b([&counter2, &totalValue, iter, iter2](){
realWork(counter2, totalValue, iter, iter2);
});
auto end = vec.end();
thread c([&counter2, &totalC, iter2, end](){
realWork(counter2, totalC, iter2, end);
}); double totalD = ;
realWork(counter2, totalD, vec.begin(), iter);
b.join();
c.join(); auto realTotalCount = counter2.count(); totalValue += totalC + totalD;
cout << "total times use multithread: " << realTotalCount << " " << totalValue << endl; printCount.join();
// (2) return ;
}
解决:原子操作变量
只需要把int m_count; 改成 atomic<int> m_count; 即可
#include <iostream>
#include <thread>
#include <chrono>
#include <future>
#include <atomic>
#include <cmath>
#include <vector>
#include <cstdlib>
#include <string>
using namespace std; class Counter
{
public:
void addCount() {
m_count++;
}
int count() const { return m_count; }
Counter() : m_count() { }
private:
// atomic_int m_count;
atomic<int> m_count; }; int work(int a)
{
return a + a;
} template<class Iter>
void realWork(Counter& c, double &totalValue, Iter b, Iter e)
{
for (; b != e; ++b)
{
totalValue += work(*b);
c.addCount();
}
} bool average(Counter& c, int maxCount)
{
auto cnt = c.count();
if (cnt == maxCount) {
cout << " ok finished \n";
return true;
}
return false;
} int main()
{
// (1) 如果没有必要的话,线程间不要共享资源
unsigned n = std::thread::hardware_concurrency();
cout << n << " concurrent threads are support.\n"; vector<int> vec;
double totalValue = ;
for (int i = ; i < ; i++)
{
vec.push_back(rand() % );
}
Counter counter;
realWork(counter, totalValue, vec.begin(), vec.end());
cout << "total times: " << counter.count() << " " << totalValue << endl; totalValue = ;
Counter counter2;
thread printCount([&counter2](){
while (!average(counter2, )) {
}
});
auto iter = vec.begin() + (vec.size() / );
auto iter2 = vec.begin() + (vec.size() / * );
double totalC = ;
//b,c 线程共享了变量 counter2, 没有共享变量 totalValue,所以totalValue一样,counter2.count()不一样
thread b([&counter2, &totalValue, iter, iter2](){
realWork(counter2, totalValue, iter, iter2);
});
auto end = vec.end();
thread c([&counter2, &totalC, iter2, end](){
realWork(counter2, totalC, iter2, end);
}); double totalD = ;
realWork(counter2, totalD, vec.begin(), iter);
b.join();
c.join(); auto realTotalCount = counter2.count(); totalValue += totalC + totalD;
cout << "total times use multithread: " << realTotalCount << " " << totalValue << endl; printCount.join(); return ;
}
3. 新需求
两个变量,其中第一个变量变化,另一个还没来得及变化,另一个线程又变化了第一个变量
4. 解决:临界区--mutex
4.1 核心部分
void lockMutex() { m_mutex.lock(); }
void unlockMutex() { m_mutex.unlock(); }
c.lockMutex();
c.addCount();
c.addResource(); c.unlockMutex();
完整代码:(不是非常好的写法)
#include <iostream>
#include <thread>
#include <chrono>
#include <future>
#include <atomic>
#include <cmath>
#include <vector>
#include <cstdlib>
#include <string>
#include <mutex>
using namespace std; class Counter
{
public:
void addCount() {
m_count++;
}
int count() const { return m_count; }
Counter() : m_count() { }
void addResource(int a) {
m_totalResource++;
}
int aveResource() {
if (m_count == )
return ;
return m_totalResource / m_count;
}
void lockMutex() { m_mutex.lock(); }
void unlockMutex() { m_mutex.unlock(); } private:
// atomic_int m_count;
atomic<int> m_count;
atomic<int> m_totalResource;
mutex m_mutex;
}; int work(int a)
{
return a + a;
} template<class Iter>
void realWork(Counter& c, double &totalValue, Iter b, Iter e)
{
for (; b != e; ++b)
{
totalValue += work(*b); c.lockMutex(); c.addCount();
c.addResource(); c.unlockMutex();
}
} bool average(Counter& c, int maxCount)
{
auto cnt = c.count(); c.lockMutex();
auto ave = c.aveResource();
if (ave != ) cout << "has bad thing happened\n";
c.unlockMutex(); if (cnt == maxCount) {
cout << " ok finished \n";
return true;
}
return false;
} int main()
{
// (1) 如果没有必要的话,线程间不要共享资源
unsigned n = std::thread::hardware_concurrency();
cout << n << " concurrent threads are support.\n"; vector<int> vec;
double totalValue = ;
for (int i = ; i < ; i++)
{
vec.push_back(rand() % );
}
Counter counter;
realWork(counter, totalValue, vec.begin(), vec.end());
cout << "total times: " << counter.count() << " " << totalValue << endl; totalValue = ;
Counter counter2;
thread printCount([&counter2](){
while (!average(counter2, )) {
}
});
auto iter = vec.begin() + (vec.size() / );
auto iter2 = vec.begin() + (vec.size() / * );
double totalC = ;
//b,c 线程共享了变量 counter2, 没有共享变量 totalValue,所以totalValue一样,counter2.count()不一样
thread b([&counter2, &totalValue, iter, iter2](){
realWork(counter2, totalValue, iter, iter2);
});
auto end = vec.end();
thread c([&counter2, &totalC, iter2, end](){
realWork(counter2, totalC, iter2, end);
}); double totalD = ;
realWork(counter2, totalD, vec.begin(), iter);
b.join();
c.join(); auto realTotalCount = counter2.count(); totalValue += totalC + totalD;
cout << "total times use multithread: " << realTotalCount << " " << totalValue << endl; printCount.join(); return ;
}
注意:使用临界区,可能会发生死锁
4.2 将锁写到接口里
#include <iostream>
#include <thread>
#include <chrono>
#include <future>
#include <atomic>
#include <cmath>
#include <vector>
#include <cstdlib>
#include <string>
#include <mutex>
using namespace std; class Counter
{
public:
Counter() : m_count(), m_totalResource() {} int count()
{
m_mutex.lock();
auto r = m_count;
m_mutex.unlock(); return r;
}
int aveResource() {
m_mutex.lock();
if (m_count == ) {
m_mutex.unlock();
return ;
}
auto r = m_totalResource / m_count;
m_mutex.unlock();
return r;
}
void addCoundAndResouce(int r)
{
m_mutex.lock();
addCount();
addResource(r);
m_mutex.unlock();
} private:
// atomic_int m_count;
void addResource(int a) {
m_totalResource++;
}
void addCount() {
m_count++;
}
int m_count;
int m_totalResource;
mutex m_mutex;
}; int work(int a)
{
return a + a;
} template<class Iter>
void realWork(Counter& c, double &totalValue, Iter b, Iter e)
{
for (; b != e; ++b)
{
totalValue += work(*b); c.addCoundAndResouce(); }
} bool average(Counter& c, int maxCount)
{
auto cnt = c.count(); auto ave = c.aveResource();
if (ave != ) cout << "has bad thing happened\n";
if (cnt == maxCount) {
cout << " ok finished \n";
return true;
}
return false;
} int main()
{
// (1) 如果没有必要的话,线程间不要共享资源
unsigned n = std::thread::hardware_concurrency();
cout << n << " concurrent threads are support.\n"; vector<int> vec;
double totalValue = ;
for (int i = ; i < ; i++)
{
vec.push_back(rand() % );
}
Counter counter;
realWork(counter, totalValue, vec.begin(), vec.end());
cout << "total times: " << counter.count() << " " << totalValue << endl; totalValue = ;
Counter counter2;
thread printCount([&counter2](){
while (!average(counter2, )) {
}
});
auto iter = vec.begin() + (vec.size() / );
auto iter2 = vec.begin() + (vec.size() / * );
double totalC = ;
//b,c 线程共享了变量 counter2, 没有共享变量 totalValue,所以totalValue一样,counter2.count()不一样
thread b([&counter2, &totalValue, iter, iter2](){
realWork(counter2, totalValue, iter, iter2);
});
auto end = vec.end();
thread c([&counter2, &totalC, iter2, end](){
realWork(counter2, totalC, iter2, end);
}); double totalD = ;
realWork(counter2, totalD, vec.begin(), iter);
b.join();
c.join(); auto realTotalCount = counter2.count(); totalValue += totalC + totalD;
cout << "total times use multithread: " << realTotalCount << " " << totalValue << endl; printCount.join(); return ;
}
如果要把 count()设置成const
class Counter
{
public:
Counter() : m_count(), m_totalResource() {} int count() const
{
m_mutex.lock();
auto r = m_count;
m_mutex.unlock(); return r;
}
int aveResource() {
m_mutex.lock();
if (m_count == ) {
m_mutex.unlock();
return ;
}
auto r = m_totalResource / m_count;
m_mutex.unlock();
return r;
}
void addCoundAndResouce(int r)
{
m_mutex.lock();
addCount();
addResource(r);
m_mutex.unlock();
} private:
// atomic_int m_count;
void addResource(int a) {
m_totalResource++;
}
void addCount() {
m_count++;
}
int m_count;
int m_totalResource;
mutable mutex m_mutex;
};
将mutex设置成mutable类型
4.3 自定义lock类
#include <iostream>
#include <thread>
#include <chrono>
#include <future>
#include <atomic>
#include <cmath>
#include <vector>
#include <cstdlib>
#include <string>
#include <mutex>
using namespace std; template<typename T>
class Lock{
public:
Lock(T& mutex) : m_mutex(mutex) {
m_mutex.lock();
}
~Lock() { m_mutex.unlock(); }
private:
T& m_mutex;
}; class Counter
{
public:
Counter() : m_count(), m_totalResource() {} int count() const
{
Lock<mutex> lock(m_mutex);
return m_count;
}
int aveResource() {
Lock<mutex> lock(m_mutex);
if (m_count == ) {
return ;
}
return m_totalResource / m_count;
}
void addCoundAndResouce(int r)
{
Lock<mutex> lock(m_mutex);
addCount();
addResource(r);
m_mutex.unlock();
} private:
// atomic_int m_count;
void addResource(int a) {
m_totalResource++;
}
void addCount() {
m_count++;
}
int m_count;
int m_totalResource;
mutable mutex m_mutex;
}; int work(int a)
{
return a + a;
} template<class Iter>
void realWork(Counter& c, double &totalValue, Iter b, Iter e)
{
for (; b != e; ++b)
{
totalValue += work(*b); c.addCoundAndResouce(); }
} bool average(Counter& c, int maxCount)
{
auto cnt = c.count(); auto ave = c.aveResource();
if (ave != ) cout << "has bad thing happened\n";
if (cnt == maxCount) {
cout << " ok finished \n";
return true;
}
return false;
} int main()
{
// (1) 如果没有必要的话,线程间不要共享资源
unsigned n = std::thread::hardware_concurrency();
cout << n << " concurrent threads are support.\n"; vector<int> vec;
double totalValue = ;
for (int i = ; i < ; i++)
{
vec.push_back(rand() % );
}
Counter counter;
realWork(counter, totalValue, vec.begin(), vec.end());
cout << "total times: " << counter.count() << " " << totalValue << endl; totalValue = ;
Counter counter2;
thread printCount([&counter2](){
while (!average(counter2, )) {
}
});
auto iter = vec.begin() + (vec.size() / );
auto iter2 = vec.begin() + (vec.size() / * );
double totalC = ;
//b,c 线程共享了变量 counter2, 没有共享变量 totalValue,所以totalValue一样,counter2.count()不一样
thread b([&counter2, &totalValue, iter, iter2](){
realWork(counter2, totalValue, iter, iter2);
});
auto end = vec.end();
thread c([&counter2, &totalC, iter2, end](){
realWork(counter2, totalC, iter2, end);
}); double totalD = ;
realWork(counter2, totalD, vec.begin(), iter);
b.join();
c.join(); auto realTotalCount = counter2.count(); totalValue += totalC + totalD;
cout << "total times use multithread: " << realTotalCount << " " << totalValue << endl; printCount.join(); return ;
}
4.4 STL中的lock_guard
上述自定义lock换成lock_guard
lock_guard更灵活
class Counter
{
public:
Counter() : m_count(), m_totalResource() {} int count() const
{
lock_guard<mutex> lock(m_mutex);
return m_count;
}
int aveResource() {
lock_guard<mutex> lock(m_mutex);
if (m_count == ) {
return ;
}
return m_totalResource / m_count;
}
void addCoundAndResouce(int r)
{
lock_guard<mutex> lock(m_mutex);
addCount();
addResource(r);
m_mutex.unlock();
} private:
// atomic_int m_count;
void addResource(int a) {
m_totalResource++;
}
void addCount() {
m_count++;
}
int m_count;
int m_totalResource;
mutable mutex m_mutex;
};
4.5 死锁
alice往bob账户转钱,线程1被锁;同时bob也往alice账户转钱,线程2被锁 ===》产生死锁
4.6 lock_guard解决死锁方案
- lock(.....): 一口气将里面的临界体mutex都锁住
- lock_guard<mutex> locka(a.mutex, adopt_lock): 告诉已经锁住了,只需要析构的时候解锁一下
深入学习c++--多线程编程(二)【当线程间需要共享非const资源】的更多相关文章
- 多线程编程-- part 4 线程间的通信
线程间的相互作用 线程之间需要一些协调通信,来共同完成一件任务. Object类相关的方法:notify(),notifyAll(),wait().会被所有的类继承,这些方法是final不能被重写.他 ...
- java多线程编程(二创建线程)
1.概念 因为java是完全面向对象的,所以在java中,我们说的线程,就是Thread类的一个实例对象.所以,一个线程就是一个对象,它有自己字段和方法. 2.创建线程 创建线程有 ...
- (Java多线程系列二)线程间同步
Java多线程间同步 1.什么是线程安全 通过一个案例了解线程安全 案例:需求现在有100张火车票,有两个窗口同时抢火车票,请使用多线程模拟抢票效果. 先来看一个线程不安全的例子 class Sell ...
- UNIX环境编程学习笔记(27)——多线程编程(二):控制线程属性
lienhua342014-11-09 1 线程属性概括 POSIX 线程的主要属性包括 scope 属性.detach 属性.堆栈地址.堆栈大小.优先级.在头文件 pthread.h 中定义了结构体 ...
- APUE学习之多线程编程(三):线程属性、同步属性
一.线程属性 可以使用pthread_attr_t结构修改线程默认属性,并这些属性和创建的线程练习起来,可以使用pthread_att_init函数初始化pthread_attr_t结构,调 ...
- APUE学习之多线程编程(一):线程的创建和销毁
一.线程标识 和每个进程都有一个进程ID一样,每个线程也有一个线程ID,线程ID是以pthread_t数据类型来表示的,在Linux中,用无符号长整型表示pthread_t,Solaris ...
- Linux程序设计学习笔记----多线程编程线程同步机制之相互排斥量(锁)与读写锁
相互排斥锁通信机制 基本原理 相互排斥锁以排他方式防止共享数据被并发訪问,相互排斥锁是一个二元变量,状态为开(0)和关(1),将某个共享资源与某个相互排斥锁逻辑上绑定之后,对该资源的訪问操作例如以下: ...
- Java多线程(二) —— 线程安全、线程同步、线程间通信(含面试题集)
一.线程安全 多个线程在执行同一段代码的时候,每次的执行结果和单线程执行的结果都是一样的,不存在执行结果的二义性,就可以称作是线程安全的. 讲到线程安全问题,其实是指多线程环境下对共享资源的访问可能会 ...
- Linux系统编程@多线程编程(二)
线程的操作 线程标识 线程的ID表示数据类型:pthread_t (内核中的实现是unsigned long/unsigned int/指向pthread结构的指针(不可移植)几种类型) 1.对两个线 ...
随机推荐
- HTTP 包体
HTTP包体:承载的消息内容 两种传输HTTP包体的方式 定长包体: 不定长包体: HTML FORM表单 HTML FORM表单提交请求时的关键属性 HTML FORM表单提交请求时的关键属性 Mu ...
- 学习Spring-Data-Jpa(三)---关联关系常用注解
1.@JoinColumn: 用于指定 连接实体关联或元素集合的列. 属性 name: 外键列的名称,它所在的表取决于上下文. 如果连接是使用外键映射策略的一对一或多对一映射,则外键列位于源实体或可嵌 ...
- BasicAuth
Go实现 在头里设置WWW-Authenticate 返回401 func (webhandler) ServeHTTP(writer http.ResponseWriter, request *ht ...
- MySQL Innodb引擎调优
介绍: Innodb给MYSQL提供了具有提交,回滚和崩溃恢复能力的事务安全(ACID兼容)存储引擎.Innodb锁定在行级并且也在SELECT语句提供一个Oracle风格一致的非锁定读.这些特色增加 ...
- web 字体 font-family
body { font-family: -apple-system, //针对 Web 页面 BlinkMacSystemFont, //针对 Mac Chrome 页面 SFProDisplay, ...
- 第一章 -- MySQL简介及安装
什么是数据库 数据库实际上就是一个文件集合,是一个存储数据的仓库,本质就是一个文件系统,数据库是按照特定的格式把数据存储起来,用户可以对存储的数据进行增删改查操作 数据库管理系统(DBMS) RDBM ...
- [分享]Passcape Software - Windows Password Recovery
[分享]Passcape Software - Windows Password Recovery https://bbs.pediy.com/thread-245965.htm [[other] ...
- JS发送验证码;并设置cookie
Tool.send_code = function(obj) { var isCheck = true, form = $('#editInfo_Form'); var mobile = form.f ...
- C静态库和动态库的制作
(一)静态库就是把一些*.o的文件集合起来:以*.a结尾打包:做成的lib库文件:专门放到lib目录下 静态库的制作: 1.制作*.a文件 把之前src/mymath.c 的源文件 编译成单独的o文件 ...
- Luogu P3391 【模板】文艺平衡树 Splay 平衡树
https://www.luogu.org/problemnew/show/P3391 以前写过题解的入门题重写练板子.wdnmd真就 ' == ' 写成 ' = ' 了编译器不报错呗. #inclu ...