线程精讲
https://paul.pub/cpp-concurrency/
- 初始化一次
#include <iostream>
#include <thread>
#include <mutex>
using namespace std;
void init()
{
cout << "Initialing..." << endl;
}
void worker(once_flag *flag)
{
call_once(*flag, init);
}
int main()
{
once_flag flag;
thread t1(worker, &flag);
thread t2(worker, &flag);
thread t3(worker, &flag);
t1.join();
t2.join();
t3.join();
return 0;
}
- 互斥体与锁
#include <iostream>
#include <thread>
#include <mutex>
#include <vector>
using namespace std;
static const int MAX = 10e8;
static double sum = 0;
static mutex exclusive;
void concurrent_worker(int min, int max)
{
double dTmp = 0;
for (int i = min; i <= max; ++i)
{
dTmp += sqrt(i);
}
exclusive.lock();
sum += dTmp;
exclusive.unlock();
}
void concurrent_task(int min, int max)
{
auto start_time = chrono::steady_clock::now();
unsigned concurrent_count = thread::hardware_concurrency();
cout << "hardware_concurrency:" << concurrent_count << endl;
vector<thread> threads;
min = 0;
sum = 0;
for (int t = 0; t < concurrent_count; ++t)
{
int range = max / concurrent_count * (t + 1);
threads.push_back(thread(concurrent_worker, min, range));
min = range + 1;
}
for (int i = 0; i < threads.size(); ++i)
{
threads[i].join();
}
auto end_time = chrono::steady_clock::now();
auto ms = chrono::duration_cast<chrono::milliseconds>(end_time - start_time).count();
cout << "Concurrent task finish, " << ms << "ms consumed, Result: " << sum << endl;
}
int main()
{
concurrent_task(0, 9999999999999999);
return 0;
}
- 避免死锁
#include <iostream>
#include <thread>
#include <mutex>
#include <vector>
#include <set>
#include <string>
using namespace std;
class Account
{
public:
Account(string name, double money) : m_name(name), m_money(money) {};
public:
void changeMoney(double amount)
{
m_money += amount;
}
string getName()
{
return m_name;
}
double getMoney()
{
return m_money;
}
mutex* getLock()
{
return &m_mtx;
}
private:
string m_name;
double m_money;
mutex m_mtx;
};
class Bank
{
public:
void addAccount(Account *account)
{
m_Accounts.insert(account);
}
bool transferMoney(Account* accountA, Account* accountB, double amount)
{
lock(*accountA->getLock(), *accountB->getLock());
lock_guard<mutex> guardA(*accountA->getLock(), adopt_lock);
lock_guard<mutex> guardB(*accountB->getLock(), adopt_lock);
if (amount > accountA->getMoney())
{
return false;
}
accountA->changeMoney(-amount);
accountB->changeMoney(+amount);
return true;
}
double totalMoney() const
{
double sum = 0;
for (auto a : m_Accounts)
{
sum += a->getMoney();
}
return sum;
}
private:
set<Account*> m_Accounts;
};
void randomTransfer(Bank* bank, Account* accountA, Account* accountB)
{
static mutex s_mtx;
while (true)
{
double randomMoney = ((double)rand() / RAND_MAX) * 100;
if (bank->transferMoney(accountA, accountB, randomMoney))
{
lock_guard<mutex> lock(s_mtx);
std::cout << "Transfer" << randomMoney << "from"
<< accountB->getName()
<< "to" << accountB->getName()
<< ",Bank totalMoney:" << bank->totalMoney() << endl;
}
else
{
lock_guard<mutex> lock(s_mtx);
cout << "Transfer failed, "
<< accountA->getName() << " has only $" << accountA->getMoney() << ", but "
<< randomMoney << " required" << endl;
}
}
}
int main()
{
Account a("Paul", 100.0);
Account b("Moiral", 100.0);
Bank bank;
bank.addAccount(&a);
bank.addAccount(&b);
thread t1(randomTransfer, &bank, &a, &b);
thread t2(randomTransfer, &bank, &b, &a);
t1.join();
t2.join();
return 0;
}
4.条件变量优化死锁
#include <iostream>
#include <thread>
#include <mutex>
#include <vector>
#include <set>
#include <string>
using namespace std;
class Account
{
public:
Account(string name, double money) : m_name(name), m_money(money) {};
public:
void changeMoney(double amount)
{
unique_lock<mutex> lock(m_mtx);
m_condition.wait(lock, [this, amount]()
{
return m_money + amount > 0;
});
m_money += amount;
m_condition.notify_all();
}
string getName()
{
return m_name;
}
double getMoney()
{
return m_money;
}
mutex* getLock()
{
return &m_mtx;
}
private:
string m_name;
double m_money;
mutex m_mtx;
condition_variable m_condition;
};
class Bank
{
public:
void addAccount(Account *account)
{
m_Accounts.insert(account);
}
bool transferMoney(Account* accountA, Account* accountB, double amount)
{
accountA->changeMoney(-amount);
accountB->changeMoney(+amount);
return true;
}
double totalMoney() const
{
double sum = 0;
for (auto a : m_Accounts)
{
sum += a->getMoney();
}
return sum;
}
private:
set<Account*> m_Accounts;
};
void randomTransfer(Bank* bank, Account* accountA, Account* accountB)
{
static mutex s_mtx;
while (true)
{
double randomMoney = ((double)rand() / RAND_MAX) * 100;
{
lock_guard<mutex> lock(s_mtx);
std::cout << "Transfer" << randomMoney << "from"
<< accountB->getName()
<< "to" << accountB->getName()
<< ",Bank totalMoney:" << bank->totalMoney() << endl;
}
bank->transferMoney(accountA, accountB, randomMoney);
}
}
int main()
{
Account a("Paul", 100.0);
Account b("Moiral", 100.0);
Bank bank;
bank.addAccount(&a);
bank.addAccount(&b);
thread t1(randomTransfer, &bank, &a, &b);
thread t2(randomTransfer, &bank, &b, &a);
t1.join();
t2.join();
return 0;
}
5.异步方式执行多线程
#include <iostream>
#include <thread>
#include <mutex>
#include <vector>
#include <set>
#include <string>
#include <future>
using namespace std;
static const int MAX = 10e8;
static double sum = 0;
void worker(int min, int max)
{
cout << "work_thread_id" << this_thread::get_id() << endl;
for (int i = min; i <= MAX; ++i)
{
sum += sqrt(i);
}
}
int main()
{
sum = 0;
cout << "main_thread_id" << this_thread::get_id() << endl;
auto f1 = async(launch::async, worker, 0, MAX);
cout << "Async task triggered" << endl;
f1.wait();
cout << "Async task finish, result: " << sum << endl;
return 0;
}
- 对类中函数执行异步线程操作
#include <iostream>
#include <thread>
#include <mutex>
#include <vector>
#include <set>
#include <string>
#include <future>
using namespace std;
class Worker
{
public:
Worker(int min, int max) : m_min(min), m_max(max){}
double work()
{
m_result = 0;
for (int i = m_min; i <= m_max; ++i)
{
m_result += sqrt(i);
}
return m_result;
}
double getResult()
{
return m_result;
}
private:
int m_min;
int m_max;
double m_result;
};
int main()
{
Worker w(0, 9999999999999999);
cout << "Task in class triggered" << endl;
auto f3 = async(&Worker::work, &w);
f3.wait();
cout << "Task in class finish, result: " << w.getResult() << endl;
return 0;
}
- packaged_task获取异步操作结果的值
#include <iostream>
#include <thread>
#include <mutex>
#include <vector>
#include <set>
#include <string>
#include <future>
using namespace std;
double concurrent_worker(int min, int max)
{
double sum = 0;
for (int i = min; i < max; ++i)
{
sum += sqrt(i);
}
return sum;
}
double concurrent_task(int min, int max)
{
vector<future<double>> results;
unsigned concurrent_count = thread::hardware_concurrency();
min = 0;
for (int i = 0; i < concurrent_count; ++i)
{
packaged_task<double(int, int)> task(concurrent_worker);
results.push_back(task.get_future());
int range = max / concurrent_count * (i + 1);
thread t(std::move(task), min, range);
t.detach();
min = range + 1;
}
cout << "threads create finish" << endl;
double sum = 0;
for (auto& r : results)
{
sum += r.get();
}
return sum;
}
int main()
{
auto start_time = chrono::steady_clock::now();
double r = concurrent_task(0, 9999);
auto end_time = chrono::steady_clock::now();
auto ms = chrono::duration_cast<chrono::microseconds>(end_time - start_time).count();
cout << "Concurrent task finish, " << ms << "ms consumed, Result:" << r << endl;
return 0;
}
- promise与future 任务结束与返回结果分开
#include <iostream>
#include <thread>
#include <mutex>
#include <vector>
#include <set>
#include <string>
#include <future>
using namespace std;
double concurrent_worker(int min, int max)
{
double sum = 0;
for (int i = min; i < max; ++i)
{
sum += sqrt(i);
}
return sum;
}
void concurrent_task(int min, int max, promise<double>* result)
{
vector<future<double>> results;
unsigned concurrent_count = thread::hardware_concurrency();
min = 0;
for (int i = 0; i < concurrent_count; ++i)
{
packaged_task<double(int, int)> task(concurrent_worker);
results.push_back(task.get_future());
int range = max / concurrent_count * (i + 1);
thread t(std::move(task), min, range);
t.detach();
min = range + 1;
}
cout << "threads create finish" << endl;
double sum = 0;
for (auto& r : results)
{
sum += r.get();
}
result->set_value(sum);
cout << "concurrent_task finish" << endl;
}
int main()
{
auto start_time = chrono::steady_clock::now();
promise<double> sum;
concurrent_task(0, 9999, &sum);
auto end_time = chrono::steady_clock::now();
auto ms = chrono::duration_cast<chrono::microseconds>(end_time - start_time).count();
cout << "Concurrent task finish, " << ms << "ms consumed, Result:" << sum.get_future().get() << endl;
return 0;
}
8.C++17的并行算法
void generateRandomData(vector<double>& collection, int size) {
random_device rd;
mt19937 mt(rd());
uniform_real_distribution<double> dist(1.0, 100.0);
for (int i = 0; i < size; i++) {
collection.push_back(dist(mt));
}
}
int main() {
vector<double> collection;
generateRandomData(collection, 10e6); // ①
vector<double> copy1(collection); // ②
vector<double> copy2(collection);
vector<double> copy3(collection);
auto time1 = chrono::steady_clock::now(); // ③
sort(execution::seq, copy1.begin(), copy1.end()); // ④
auto time2 = chrono::steady_clock::now();
auto duration = chrono::duration_cast<chrono::milliseconds>(time2 - time1).count();
cout << "Sequenced sort consuming " << duration << "ms." << endl; // ⑤
auto time3 = chrono::steady_clock::now();
sort(execution::par, copy2.begin(), copy2.end()); // ⑥
auto time4 = chrono::steady_clock::now();
duration = chrono::duration_cast<chrono::milliseconds>(time4 - time3).count();
cout << "Parallel sort consuming " << duration << "ms." << endl;
auto time5 = chrono::steady_clock::now();
sort(execution::par_unseq, copy2.begin(), copy2.end()); // ⑦
auto time6 = chrono::steady_clock::now();
duration = chrono::duration_cast<chrono::milliseconds>(time6 - time5).count();
cout << "Parallel unsequenced sort consuming " << duration << "ms." << endl;
}