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(0) { }
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 = 0;
for (int i = 0; i < 10000000; i++)
{
vec.push_back(rand() % 100);
}
Counter counter;
realWork(counter, totalValue, vec.begin(), vec.end());
cout << "total times: " << counter.count() << " " << totalValue << endl;
totalValue = 0;
Counter counter2;
auto iter = vec.begin() + (vec.size() / 3);
auto iter2 = vec.begin() + (vec.size() / 3 * 2);
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 0;
}
计算结果不一致!三个线程共享一份资源,有的加了有的没加。
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(0) { }
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 = 0;
for (int i = 0; i < 10000000; i++)
{
vec.push_back(rand() % 100);
}
Counter counter;
realWork(counter, totalValue, vec.begin(), vec.end());
cout << "total times: " << counter.count() << " " << totalValue << endl;
totalValue = 0;
Counter counter2;
auto iter = vec.begin() + (vec.size() / 3);
auto iter2 = vec.begin() + (vec.size() / 3 * 2);
double totalC = 0;
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 = 0;
realWork(counter2, totalD, vec.begin(), iter);
b.join();
c.join();
cout << "total times use multithread: " << counter2.count() << " " << totalValue+totalC+totalD << endl;
return 0;
}
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(0) { }
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 = 3;
int b = 4;
int c = 5;
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 = 0;
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 = 0;
for (int i = 0; i < 10000000; i++)
{
vec.push_back(rand() % 100);
}
Counter counter;
realWork(counter, totalValue, vec.begin(), vec.end());
cout << "total times: " << counter.count() << " " << totalValue << endl;
totalValue = 0;
Counter counter2;
thread printCount([&counter2](){
while (!average(counter2, 10000000)) {
}
});
auto iter = vec.begin() + (vec.size() / 3);
auto iter2 = vec.begin() + (vec.size() / 3 * 2);
double totalC = 0;
//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 = 0;
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 0;
}
解决:原子操作变量
只需要把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(0) { }
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 = 0;
for (int i = 0; i < 10000000; i++)
{
vec.push_back(rand() % 100);
}
Counter counter;
realWork(counter, totalValue, vec.begin(), vec.end());
cout << "total times: " << counter.count() << " " << totalValue << endl;
totalValue = 0;
Counter counter2;
thread printCount([&counter2](){
while (!average(counter2, 10000000)) {
}
});
auto iter = vec.begin() + (vec.size() / 3);
auto iter2 = vec.begin() + (vec.size() / 3 * 2);
double totalC = 0;
//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 = 0;
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 0;
}
3. 新需求
两个变量,其中第一个变量变化,另一个还没来得及变化,另一个线程又变化了第一个变量
4. 解决:临界区--mutex
核心:
void lockMutex() { m_mutex.lock(); }
void unlockMutex() { m_mutex.unlock(); }
c.lockMutex();
c.addCount();
c.addResource(1);
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(0) { }
void addResource(int a) {
m_totalResource++;
}
int aveResource() {
if (m_count == 0)
return 1;
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(1);
c.unlockMutex();
}
}
bool average(Counter& c, int maxCount)
{
auto cnt = c.count();
c.lockMutex();
auto ave = c.aveResource();
if (ave != 1) 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 = 0;
for (int i = 0; i < 10000000; i++)
{
vec.push_back(rand() % 100);
}
Counter counter;
realWork(counter, totalValue, vec.begin(), vec.end());
cout << "total times: " << counter.count() << " " << totalValue << endl;
totalValue = 0;
Counter counter2;
thread printCount([&counter2](){
while (!average(counter2, 10000000)) {
}
});
auto iter = vec.begin() + (vec.size() / 3);
auto iter2 = vec.begin() + (vec.size() / 3 * 2);
double totalC = 0;
//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 = 0;
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 0;
}
注意:使用临界区,可能会发生死锁