c++ 11 14 17 20後的新特性總結三:執行緒、期物、互斥量與臨界區、條件變數、原子操作、記憶體模型
阿新 • • 發佈:2020-12-19
技術標籤:C++技術
c++併發與同步特性
thread、future、mutex、lock、atomic、memory_order
#include <thread>
#include <chrono>//時間
int threadFun(const char* str)
{
cout<<str<<endl;
return str==nullptr ? 13:14;
}
void thread_create()
{
std::thread t([](){
cout<<"thread start " <<endl;
//sleep(3);
std::this_thread::sleep_for(chrono::seconds(5));
});
cout<<"wait tthread"<<endl;
t.join();
cout<<"tthread finished"<<endl;
//帶參執行緒
std::thread p(threadFun, "zyc");
cout<<"wait pthread" <<endl;
p.join();
cout<<"pthread finished"<<endl;
}
#include <mutex>
//std::lock_guard
class lock_thread final:public thread
{
public:
void start_test(int num)
{
std::lock_guard<std::mutex> lock(m_mtx);
cout<<"start " <<num<<endl;
std::this_thread::sleep_for(chrono::seconds(1));
}
//std::unique_lock
void uinque_test(int num)
{
std::unique_lock<std::mutex> lock(m_uniqueMtx);
cout<<"start "<<num<<endl;
std::this_thread::sleep_for(chrono::seconds(2));
lock.unlock();
std::this_thread::sleep_for(chrono::seconds(1));
lock.lock();
cout<<"restart "<<num<<endl;
std::this_thread::sleep_for(chrono::seconds(3));
}
private:
std::mutex m_mtx;
std::mutex m_uniqueMtx;
};
void lock_guard_test()
{
static lock_thread lthread;//lock_thread lthread();報錯——因為不帶引數的建構函式,比如lthread()它可以是一個物件,也可是一個函式宣告。但是c++編譯器總是優先認為是一個函式宣告,然後是物件。
lthread.start_test(3);
lthread.start_test(6);
//
std::thread t([](){
lthread.uinque_test(2);
});
std::thread p([](){
lthread.uinque_test(4);
});
t.join();
p.join();
}
//std::future:訪問非同步操作結果的途徑(非同步事件完成通知)
#include <future>
void future_test()
{
std::packaged_task<int()> task([](){
//std::this_thread::sleep_for(chrono::seconds(3));
return 8;
});
std::future<int> result = task.get_future();
std::thread(std::move(task)).detach();
//cout<<"waiting... "<<result.get()<<endl;
result.wait();
cout<<"result is "<<result.get()<<endl;
}
/*std::condition_variable:解決互斥操作中需要等待某個條件為真才繼續執行,
* 造成的致所有其他執行緒都無法進入臨界區使得條件為真的死鎖問題
* 生產者——消費者問題
*/
#include<condition_variable>
#include <queue>
void conditionV()
{
std::queue<int> que;
std::mutex mtx;
std::condition_variable cv;
std::atomic<bool> notified(false);//bool型別-原子操作
auto producer = [&](){
for(int i=0;;++i)
{
std::this_thread::sleep_for(chrono::milliseconds(3000));
std::unique_lock<std::mutex> lock(mtx);
que.emplace(i);
notified = true;
cv.notify_all();
cout<<"producer notify_all"<<endl;
}
};
auto consumer = [&](){
do
{
std::unique_lock<std::mutex> lock(mtx);
while(!notified)
cv.wait(lock);
lock.unlock();
std::this_thread::sleep_for(chrono::milliseconds(2000));//兩個消費者,導致消費比生產快
lock.lock();
if(!que.empty())//每次取一個
{
cout<<"consumer pop "<<que.front()<<endl;
que.pop();
}
notified = false;
}while(1);
};
std::thread p(producer);
std::thread c(consumer);
std::thread c1(consumer);
p.join();
c.join();
c1.join();
}
//原子操作——單個執行緒可能出現指令重排(後面語句先於之前執行)
#include<atomic>
void atomic_test()
{
std::atomic_int atmc(0);
std::thread t([&](){
atmc++;
});
std::thread p([&](){
atmc.fetch_add(2);
});
t.join();
p.join();
cout<<"is support "<<std::boolalpha<<atmc.is_lock_free()<<endl;//std::boolalpha:使bool以true/false字母輸出
}
//記憶體模型:std::memory_order
void memory_order_test()
{
//寬鬆模型
std::atomic<int> counter = {0};
std::vector<std::thread> vt;
for (int i = 0; i < 100; ++i) {
vt.emplace_back([&](){
counter.fetch_add(1, std::memory_order_relaxed);
});
}
for (auto& t : vt) {
t.join();
}
std::cout << "current counter:" << counter << std::endl;
#if 0
//釋放/消費模型
std::atomic<int*> ptr(nullptr);
int v;
std::thread producer([&]() {
int* p = new int(42);
v = 1024;
ptr.store(p, std::memory_order_release);
});
std::thread consumer([&]() {
int* p;
while(!(p = ptr.load(std::memory_order_consume)));
std::cout << "p: " << *p << std::endl;
std::cout << "v: " << v << std::endl;
});
producer.join();
consumer.join();
//釋放/獲取模型
std::vector<int> v;
std::atomic<int> flag = {0};
std::thread release([&]() {
v.push_back(42);
flag.store(1, std::memory_order_release);
});
std::thread acqrel([&]() {
int expected = 1; // must before compare_exchange_strong
while(!flag.compare_exchange_strong(expected, 2, std::memory_order_acq_rel)) {
expected = 1; // must after compare_exchange_strong
}
// flag has changed to 2
});
std::thread acquire([&]() {
while(flag.load(std::memory_order_acquire) < 2);
std::cout << v.at(0) << std::endl; // must be 42
});
release.join();
acqrel.join();
acquire.join();
//順序一致模型
std::atomic<int> counter = {0};
std::vector<std::thread> vt;
for (int i = 0; i < 100; ++i) {
vt.emplace_back([&](){
counter.fetch_add(1, std::memory_order_seq_cst);
});
}
for (auto& t : vt) {
t.join();
}
std::cout << "current counter:" << counter << std::endl;
#endif
}