๐คฃParallelism and Concurrency
https://changkun.de/modern-cpp/en-us/07-thread/#7-1-Basic-of-Parallelism
Basic
std::thread
็จไบๅๅปบไธไธชๆง่ก็็บฟ็จๅฎไพ๏ผๆไปฅๅฎๆฏไธๅๅนถๅ็ผ็จ็ๅบ็ก๏ผไฝฟ็จๆถ้่ฆๅ
ๅซ <thread>
ๅคดๆไปถ๏ผ ๅฎๆไพไบๅพๅคๅบๆฌ็็บฟ็จๆไฝ๏ผไพๅฆ get_id()
ๆฅ่ทๅๆๅๅปบ็บฟ็จ็็บฟ็จ ID๏ผไฝฟ็จ join()
ๆฅๅ ๅ
ฅไธไธช็บฟ็จ็ญ็ญ๏ผไพๅฆ๏ผ
#include <iostream>
#include <thread>
int main() {
std::thread t([](){
std::cout << "hello world." << std::endl;
});
t.join();
return 0;
}
Mutex and Critical Section
std::mutex
ๆฏ C++11 ไธญๆๅบๆฌ็ mutex
็ฑป๏ผ้่ฟๅฎไพๅ std::mutex
ๅฏไปฅๅๅปบไบๆฅ้๏ผ ่้่ฟๅ
ถๆๅๅฝๆฐ lock()
ๅฏไปฅ่ฟ่กไธ้๏ผunlock()
ๅฏไปฅ่ฟ่ก่งฃ้ใ ไฝๆฏๅจๅฎ้
็ผๅไปฃ็ ็่ฟ็จไธญ๏ผๆๅฅฝไธๅป็ดๆฅ่ฐ็จๆๅๅฝๆฐ๏ผ ๅ ไธบ่ฐ็จๆๅๅฝๆฐๅฐฑ้่ฆๅจๆฏไธชไธด็ๅบ็ๅบๅฃๅค่ฐ็จ unlock()
๏ผๅฝ็ถ๏ผ่ฟๅ
ๆฌๅผๅธธใ
่ฟๆถๅ C++11 ่ฟไธบไบๆฅ้ๆไพไบไธไธช RAII ่ฏญๆณ็ๆจกๆฟ็ฑป std::lock_guard
ใ RAII ๅจไธๅคฑไปฃ็ ็ฎๆดๆง็ๅๆถ๏ผๅพๅฅฝ็ไฟ่ฏไบไปฃ็ ็ๅผๅธธๅฎๅ
จๆงใ
ๅจ RAII ็จๆณไธ๏ผๅฏนไบไธด็ๅบ็ไบๆฅ้็ๅๅปบๅช้่ฆๅจไฝ็จๅ็ๅผๅง้จๅ๏ผไพๅฆ๏ผ
#include <iostream>
#include <mutex>
#include <thread>
int v = 1;
void critical_section(int change_v) {
static std::mutex mtx;
std::lock_guard<std::mutex> lock(mtx);
// ๆง่ก็ซไบๆไฝ
v = change_v;
// ็ฆปๅผๆญคไฝ็จๅๅ mtx ไผ่ขซ้ๆพ
}
int main() {
std::thread t1(critical_section, 2), t2(critical_section, 3);
t1.join();
t2.join();
std::cout << v << std::endl;
return 0;
}
็ฑไบ C++ ไฟ่ฏไบๆๆๆ ๅฏน่ฑกๅจ็ๅฝๅจๆ็ปๆๆถไผ่ขซ้ๆฏ๏ผๆไปฅ่ฟๆ ท็ไปฃ็ ไนๆฏๅผๅธธๅฎๅ
จ็ใ ๆ ่ฎบ critical_section()
ๆญฃๅธธ่ฟๅใ่ฟๆฏๅจไธญ้ๆๅบๅผๅธธ๏ผ้ฝไผๅผๅๅ ๆ ๅ้๏ผไนๅฐฑ่ชๅจ่ฐ็จไบ unlock()
ใ
่ std::unique_lock
ๅๆฏ็ธๅฏนไบ std::lock_guard
ๅบ็ฐ็๏ผstd::unique_lock
ๆดๅ ็ตๆดป๏ผ std::unique_lock
็ๅฏน่ฑกไผไปฅ็ฌๅ ๆๆๆ๏ผๆฒกๆๅ
ถไป็ unique_lock
ๅฏน่ฑกๅๆถๆฅๆๆไธช mutex
ๅฏน่ฑก็ๆๆๆ๏ผ ็ๆนๅผ็ฎก็ mutex
ๅฏน่ฑกไธ็ไธ้ๅ่งฃ้็ๆไฝใๆไปฅๅจๅนถๅ็ผ็จไธญ๏ผๆจ่ไฝฟ็จ std::unique_lock
ใ
std::lock_guard
ไธ่ฝๆพๅผ็่ฐ็จ lock
ๅ unlock
๏ผ ่ std::unique_lock
ๅฏไปฅๅจๅฃฐๆๅ็ไปปๆไฝ็ฝฎ่ฐ็จ๏ผ ๅฏไปฅ็ผฉๅฐ้็ไฝ็จ่ๅด๏ผๆไพๆด้ซ็ๅนถๅๅบฆใ
ๅฆๆไฝ ็จๅฐไบๆกไปถๅ้ std::condition_variable::wait
ๅๅฟ
้กปไฝฟ็จ std::unique_lock
ไฝไธบๅๆฐใ
Futher
ๆ็ฉ๏ผFuture๏ผ่กจ็ฐไธบ std::future
๏ผๅฎๆไพไบไธไธช่ฎฟ้ฎๅผๆญฅๆไฝ็ปๆ็้ๅพ๏ผ่ฟๅฅ่ฏๅพไธๅฅฝ็่งฃใ ไธบไบ็่งฃ่ฟไธช็นๆง๏ผๆไปฌ้่ฆๅ
็่งฃไธไธๅจ C++11 ไนๅ็ๅค็บฟ็จ่กไธบใ
่ฏๆณ๏ผๅฆๆๆไปฌ็ไธป็บฟ็จ A ๅธๆๆฐๅผ่พไธไธช็บฟ็จ B ๅปๆง่กๆไธชๆไปฌ้ขๆ็ไปปๅก๏ผๅนถ่ฟๅๆไธไธช็ปๆใ ่่ฟๆถๅ๏ผ็บฟ็จ A ๅฏ่ฝๆญฃๅจๅฟๅ ถไป็ไบๆ ๏ผๆ ๆ้กพๅ B ็็ปๆ๏ผ ๆไปฅๆไปฌไผๅพ่ช็ถ็ๅธๆ่ฝๅคๅจๆไธช็นๅฎ็ๆถ้ด่ทๅพ็บฟ็จ B ็็ปๆใ
ๅจ C++11 ็ std::future
่ขซๅผๅ
ฅไนๅ๏ผ้ๅธธ็ๅๆณๆฏ๏ผ ๅๅปบไธไธช็บฟ็จ A๏ผๅจ็บฟ็จ A ้ๅฏๅจไปปๅก B๏ผๅฝๅๅคๅฎๆฏๅๅ้ไธไธชไบไปถ๏ผๅนถๅฐ็ปๆไฟๅญๅจๅ
จๅฑๅ้ไธญใ ่ไธปๅฝๆฐ็บฟ็จ A ้ๆญฃๅจๅๅ
ถไป็ไบๆ
๏ผๅฝ้่ฆ็ปๆ็ๆถๅ๏ผ่ฐ็จไธไธช็บฟ็จ็ญๅพ
ๅฝๆฐๆฅ่ทๅพๆง่ก็็ปๆใ
่ C++11 ๆไพ็ std::future
็ฎๅไบ่ฟไธชๆต็จ๏ผๅฏไปฅ็จๆฅ่ทๅๅผๆญฅไปปๅก็็ปๆใ ่ช็ถๅฐ๏ผๆไปฌๅพๅฎนๆ่ฝๅคๆณ่ฑกๅฐๆๅฎไฝไธบไธ็ง็ฎๅ็็บฟ็จๅๆญฅๆๆฎต๏ผๅณๅฑ้๏ผbarrier๏ผใ
ไธบไบ็ไธไธชไพๅญ๏ผๆไปฌ่ฟ้้ขๅคไฝฟ็จ std::packaged_task
๏ผๅฎๅฏไปฅ็จๆฅๅฐ่ฃ
ไปปไฝๅฏไปฅ่ฐ็จ็็ฎๆ ๏ผไป่็จไบๅฎ็ฐๅผๆญฅ็่ฐ็จใ ไธพไพๆฅ่ฏด๏ผ
#include <iostream>
#include <future>
#include <thread>
int main() {
// ๅฐไธไธช่ฟๅๅผไธบ7็ lambda ่กจ่พพๅผๅฐ่ฃ
ๅฐ task ไธญ
// std::packaged_task ็ๆจกๆฟๅๆฐไธบ่ฆๅฐ่ฃ
ๅฝๆฐ็็ฑปๅ
std::packaged_task<int()> task([](){return 7;});
// ่ทๅพ task ็ๆ็ฉ
std::future<int> result = task.get_future(); // ๅจไธไธช็บฟ็จไธญๆง่ก task
std::thread(std::move(task)).detach(); // move: ็งปๅจๆ้ ๅฝๆฐ
std::cout << "waiting...";
result.wait(); // ๅจๆญค่ฎพ็ฝฎๅฑ้๏ผ้ปๅกๅฐๆ็ฉ็ๅฎๆ
// ่พๅบๆง่ก็ปๆ
std::cout << "done!" << std:: endl << "future result is "
<< result.get() << std::endl;
return 0;
}
ๅจๅฐ่ฃ
ๅฅฝ่ฆ่ฐ็จ็็ฎๆ ๅ๏ผๅฏไปฅไฝฟ็จ get_future()
ๆฅ่ทๅพไธไธช std::future
ๅฏน่ฑก๏ผไปฅไพฟไนๅๅฎๆฝ็บฟ็จๅๆญฅใ
Condition Variable
ๆกไปถๅ้ std::condition_variable
ๆฏไธบไบ่งฃๅณๆญป้่็๏ผๅฝไบๆฅๆไฝไธๅค็จ่ๅผๅ
ฅ็ใ ๆฏๅฆ๏ผ็บฟ็จๅฏ่ฝ้่ฆ็ญๅพ
ๆไธชๆกไปถไธบ็ๆ่ฝ็ปง็ปญๆง่ก๏ผ ่ไธไธชๅฟ็ญๅพ
ๅพช็ฏไธญๅฏ่ฝไผๅฏผ่ดๆๆๅ
ถไป็บฟ็จ้ฝๆ ๆณ่ฟๅ
ฅไธด็ๅบไฝฟๅพๆกไปถไธบ็ๆถ๏ผๅฐฑไผๅ็ๆญป้ใ ๆไปฅ๏ผcondition_variable
ๅฎไพ่ขซๅๅปบๅบ็ฐไธป่ฆๅฐฑๆฏ็จไบๅค้็ญๅพ
็บฟ็จไป่้ฟๅ
ๆญป้ใ std::condition_variable
็ notify_one()
็จไบๅค้ไธไธช็บฟ็จ๏ผ notify_all()
ๅๆฏ้็ฅๆๆ็บฟ็จใไธ้ขๆฏไธไธช็ไบง่
ๅๆถ่ดน่
ๆจกๅ็ไพๅญ๏ผ
#include <queue>
#include <chrono>
#include <mutex>
#include <thread>
#include <iostream>
#include <condition_variable>
int main() {
std::queue<int> produced_nums;
std::mutex mtx;
std::condition_variable cv;
bool notified = false; // ้็ฅไฟกๅท
// ็ไบง่
auto producer = [&]() {
for (int i = 0; ; i++) {
std::this_thread::sleep_for(std::chrono::milliseconds(900));
std::unique_lock<std::mutex> lock(mtx);
std::cout << "producing " << i << std::endl;
produced_nums.push(i);
notified = true;
cv.notify_all(); // ๆญคๅคไนๅฏไปฅไฝฟ็จ notify_one
}
};
// ๆถ่ดน่
auto consumer = [&]() {
while (true) {
std::unique_lock<std::mutex> lock(mtx);
while (!notified) { // ้ฟๅ
่ๅๅค้
cv.wait(lock);
}
// ็ญๆๅๆถ้๏ผไฝฟๅพ็ไบง่
ๆๆบไผๅจๆถ่ดน่
ๆถ่ดน็ฉบๅ็ปง็ปญ็ไบง
lock.unlock();
// ๆถ่ดน่
ๆ
ขไบ็ไบง่
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
lock.lock();
while (!produced_nums.empty()) {
std::cout << "consuming " << produced_nums.front() << std::endl;
produced_nums.pop();
}
notified = false;
}
};
// ๅๅซๅจไธๅ็็บฟ็จไธญ่ฟ่ก
std::thread p(producer);
std::thread cs[2];
for (int i = 0; i < 2; ++i) {
cs[i] = std::thread(consumer);
}
p.join();
for (int i = 0; i < 2; ++i) {
cs[i].join();
}
return 0;
}
ๅผๅพไธๆ็ๆฏ๏ผๅจ็ไบง่
ไธญๆไปฌ่ฝ็ถๅฏไปฅไฝฟ็จ notify_one()
๏ผไฝๅฎ้
ไธๅนถไธๅปบ่ฎฎๅจๆญคๅคไฝฟ็จ๏ผ ๅ ไธบๅจๅคๆถ่ดน่
็ๆ
ๅตไธ๏ผๆไปฌ็ๆถ่ดน่
ๅฎ็ฐไธญ็ฎๅๆพๅผไบ้็ๆๆ๏ผ่ฟไฝฟๅพๅฏ่ฝ่ฎฉๅ
ถไปๆถ่ดน่
ไบๅคบๆญค้๏ผไป่ๆดๅฅฝ็ๅฉ็จๅคไธชๆถ่ดน่
ไน้ด็ๅนถๅใ่ฏ่ฝๅฆๆญค๏ผไฝๅฎ้
ไธๅ ไธบ std::mutex
็ๆไปๆง๏ผ ๆไปฌๆ นๆฌๆ ๆณๆๅพ
ๅคไธชๆถ่ดน่
่ฝ็ๆญฃๆไนไธ็ๅนถ่กๆถ่ดน้ๅ็ไธญ็ไบง็ๅ
ๅฎน๏ผๆไปฌไป้่ฆ็ฒๅบฆๆด็ป็ๆๆฎตใ
ๅๅญๆไฝไธๅ
ๅญๆจกๅ
็ปๅฟ็่ฏป่
ๅฏ่ฝไผๅฏนๅไธๅฐ่ไธญ็ไบง่
ๆถ่ดน่
ๆจกๅ็ไพๅญๅฏ่ฝๅญๅจ็ผ่ฏๅจไผๅๅฏผ่ด็จๅบๅบ้็ๆ
ๅตไบง็็ๆใ ไพๅฆ๏ผๅธๅฐๅผ notified
ๆฒกๆ่ขซ volatile
ไฟฎ้ฅฐ๏ผ็ผ่ฏๅจๅฏ่ฝๅฏนๆญคๅ้ๅญๅจไผๅ๏ผไพๅฆๅฐๅ
ถไฝไธบไธไธชๅฏๅญๅจ็ๅผ๏ผ ไป่ๅฏผ่ดๆถ่ดน่
็บฟ็จๆฐธ่ฟๆ ๆณ่งๅฏๅฐๆญคๅผ็ๅๅใ่ฟๆฏไธไธชๅฅฝ้ฎ้ข๏ผไธบไบ่งฃ้ๆธ
ๆฅ่ฟไธช้ฎ้ข๏ผๆไปฌ้่ฆ่ฟไธๆญฅ่ฎจ่ฎบ ไป C++ 11 ่ตทๅผๅ
ฅ็ๅ
ๅญๆจกๅ่ฟไธๆฆๅฟตใๆไปฌ้ฆๅ
ๆฅ็ไธไธช้ฎ้ข๏ผไธ้ข่ฟๆฎตไปฃ็ ่พๅบ็ปๆๆฏๅคๅฐ๏ผ
#include <thread>
#include <iostream>
int main() {
int a = 0;
int flag = 0;
std::thread t1([&]() {
while (flag != 1);
int b = a;
std::cout << "b = " << b << std::endl;
});
std::thread t2([&]() {
a = 5;
flag = 1;
});
t1.join();
t2.join();
return 0;
}
ไป็ด่งไธ็๏ผt2
ไธญ a = 5;
่ฟไธๆก่ฏญๅฅไผผไนๆปๅจ flag = 1;
ไนๅๅพๅฐๆง่ก๏ผ่ t1
ไธญ while (flag != 1)
ไผผไนไฟ่ฏไบ std::cout << "b = " << b << std::endl;
ไธไผๅๆ ่ฎฐ่ขซๆนๅๅๆง่กใไป้ป่พไธ็๏ผไผผไน b
็ๅผๅบ่ฏฅ็ญไบ 5ใ ไฝๅฎ้
ๆ
ๅต่ฟๆฏๆญคๅคๆๅพๅค๏ผๆ่
่ฏด่ฟๆฎตไปฃ็ ๆฌ่บซๅฑไบๆชๅฎไน็่กไธบ๏ผๅ ไธบๅฏนไบ a
ๅ flag
่่จ๏ผไปไปฌๅจไธคไธชๅนถ่ก็็บฟ็จไธญ่ขซ่ฏปๅ๏ผ ๅบ็ฐไบ็ซไบใ้คๆญคไนๅค๏ผๅณไพฟๆไปฌๅฟฝ็ฅ็ซไบ่ฏปๅ๏ผไป็ถๅฏ่ฝๅ CPU ็ไนฑๅบๆง่ก๏ผ็ผ่ฏๅจๅฏนๆไปค็้ๆ็ๅฝฑๅ๏ผ ๅฏผ่ด a = 5
ๅ็ๅจ flag = 1
ไนๅใไป่ b
ๅฏ่ฝ่พๅบ 0ใ
ๅๅญๆไฝ
std::mutex
ๅฏไปฅ่งฃๅณไธ้ขๅบ็ฐ็ๅนถๅ่ฏปๅ็้ฎ้ข๏ผไฝไบๆฅ้ๆฏๆไฝ็ณป็ป็บง็ๅ่ฝ๏ผ ่ฟๆฏๅ ไธบไธไธชไบๆฅ้็ๅฎ็ฐ้ๅธธๅ
ๅซไธคๆกๅบๆฌๅ็๏ผ
ๆไพ็บฟ็จ้ด่ชๅจ็็ถๆ่ฝฌๆข๏ผๅณใ้ไฝใ่ฟไธช็ถๆ
ไฟ้ๅจไบๆฅ้ๆไฝๆ้ด๏ผๆๆไฝๅ้็ๅ ๅญไธไธด็ๅบๅค่ฟ่ก้็ฆป
่ฟๆฏไธ็ป้ๅธธๅผบ็ๅๆญฅๆกไปถ๏ผๆขๅฅ่ฏ่ฏดๅฝๆ็ป็ผ่ฏไธบ CPU ๆไปคๆถไผ่กจ็ฐไธบ้ๅธธๅค็ๆไปค๏ผๆไปฌไนๅๅๆฅ็ๅฆไฝๅฎ็ฐไธไธช็ฎๅ็ไบๆฅ้๏ผใ ่ฟๅฏนไบไธไธชไป ้ๅๅญ็บงๆไฝ๏ผๆฒกๆไธญ้ดๆ๏ผ็ๅ้๏ผไผผไนๅคช่ๅปไบใ
ๅ
ณไบๅๆญฅๆกไปถ็็ ็ฉถๆ็้ๅธธไน
่ฟ็ๅๅฒ๏ผๆไปฌๅจ่ฟ้ไธ่ฟ่ก่ต่ฟฐใ่ฏป่
ๅบ่ฏฅๆ็ฝ๏ผ็ฐไปฃ CPU ไฝ็ณป็ปๆๆไพไบ CPU ๆไปค็บง็ๅๅญๆไฝ๏ผ ๅ ๆญคๅจ C++11 ไธญๅค็บฟ็จไธๅ
ฑไบซๅ้็่ฏปๅ่ฟไธ้ฎ้ขไธ๏ผ่ฟๅผๅ
ฅไบ std::atomic
ๆจกๆฟ๏ผไฝฟๅพๆไปฌๅฎไพๅไธไธชๅๅญ็ฑปๅ๏ผๅฐไธไธช ๅๅญ็ฑปๅ่ฏปๅๆไฝไปไธ็ปๆไปค๏ผๆๅฐๅๅฐๅไธช CPU ๆไปคใไพๅฆ๏ผ
std::atomic<int> counter;
ๅนถไธบๆดๆฐๆๆตฎ็นๆฐ็ๅๅญ็ฑปๅๆไพไบๅบๆฌ็ๆฐๅผๆๅๅฝๆฐ๏ผไธพไพๆฅ่ฏด๏ผ ๅ
ๆฌ fetch_add
, fetch_sub
็ญ๏ผๅๆถ้่ฟ้่ฝฝๆนไพฟ็ๆไพไบๅฏนๅบ็ +
๏ผ-
็ๆฌใ ๆฏๅฆไธ้ข็ไพๅญ๏ผ
#include <atomic>
#include <thread>
#include <iostream>
std::atomic<int> count = {0};
int main() {
std::thread t1([](){
count.fetch_add(1);
});
std::thread t2([](){
count++; // ็ญไปทไบ fetch_add
count += 1; // ็ญไปทไบ fetch_add
});
t1.join();
t2.join();
std::cout << count << std::endl;
return 0;
}
ๅฝ็ถ๏ผๅนถ้ๆๆ็็ฑปๅ้ฝ่ฝๆไพๅๅญๆไฝ๏ผ่ฟๆฏๅ ไธบๅๅญๆไฝ็ๅฏ่กๆงๅๅณไบๅ
ทไฝ็ CPU ๆถๆ๏ผไปฅๅๆๅฎไพๅ็็ฑปๅ็ปๆๆฏๅฆ่ฝๅคๆปก่ถณ่ฏฅ CPU ๆถๆๅฏนๅ
ๅญๅฏน้ฝ ๆกไปถ็่ฆๆฑ๏ผๅ ่ๆไปฌๆปๆฏๅฏไปฅ้่ฟ std::atomic<T>::is_lock_free
ๆฅๆฃๆฅ่ฏฅๅๅญ็ฑปๅๆฏๅฆ้ๆฏๆๅๅญๆไฝ๏ผไพๅฆ๏ผ
#include <atomic>
#include <iostream>
struct A {
float x;
int y;
long long z;
};
int main() {
std::atomic<A> a;
std::cout << std::boolalpha << a.is_lock_free() << std::endl;
return 0;
}
ไธ่ดๆงๆจกๅ
ๅนถ่กๆง่ก็ๅคไธช็บฟ็จ๏ผไปๆ็งๅฎ่งๅฑ้ขไธ่ฎจ่ฎบ๏ผๅฏไปฅ็ฒ็ฅ็่งไธบไธ็งๅๅธๅผ็ณป็ปใ ๅจๅๅธๅผ็ณป็ปไธญ๏ผไปปไฝ้ไฟกไน่ณๆฌๅฐๆไฝ้ฝ้่ฆๆถ่ไธๅฎๆถ้ด๏ผ็่ณๅบ็ฐไธๅฏ้ ็้ไฟกใ
ๅฆๆๆไปฌๅผบ่กๅฐไธไธชๅ้ v
ๅจๅคไธช็บฟ็จไน้ด็ๆไฝ่ฎพไธบๅๅญๆไฝ๏ผๅณไปปไฝไธไธช็บฟ็จๅจๆไฝๅฎ v
ๅ๏ผ ๅ
ถไป็บฟ็จๅ่ฝๅๆญฅๆ็ฅๅฐ v
็ๅๅ๏ผๅๅฏนไบๅ้ v
่่จ๏ผ่กจ็ฐไธบ้กบๅบๆง่ก็็จๅบ๏ผๅฎๅนถๆฒกๆ็ฑไบๅผๅ
ฅๅค็บฟ็จ ่ๅพๅฐไปปไฝๆ็ไธ็ๆถ็ใๅฏนๆญคๆไปไนๅๆณ่ฝๅค้ๅฝ็ๅ ้ๅข๏ผ็ญๆกไพฟๆฏๅๅผฑๅๅญๆไฝ็ๅจ่ฟ็จ้ด็ๅๆญฅๆกไปถใ
ไปๅ็ไธ็๏ผๆฏไธช็บฟ็จๅฏไปฅๅฏนๅบไธบไธไธช้็พค่็น๏ผ่็บฟ็จ้ด็้ไฟกไนๅ ไน็ญไปทไบ้็พค่็น้ด็้ไฟกใ ๅๅผฑ่ฟ็จ้ด็ๅๆญฅๆกไปถ๏ผ้ๅธธๆไปฌไผ่่ๅ็งไธๅ็ไธ่ดๆงๆจกๅ๏ผ
็บฟๆงไธ่ดๆง๏ผๅ็งฐๅผบไธ่ดๆงๆๅๅญไธ่ดๆงใๅฎ่ฆๆฑไปปไฝไธๆฌก่ฏปๆไฝ้ฝ่ฝ่ฏปๅฐๆไธชๆฐๆฎ็ๆ่ฟไธๆฌกๅ็ๆฐๆฎ๏ผๅนถไธๆๆ็บฟ็จ็ๆไฝ้กบๅบไธๅ จๅฑๆถ้ไธ็้กบๅบๆฏไธ่ด็ใ
x.store(1) x.load()
T1 ---------+----------------+------>
T2 -------------------+------------->
x.store(2)
ๅจ่ฟ็งๆ
ๅตไธ็บฟ็จ T1
, T2
ๅฏน x
็ไธคๆฌกๅๆไฝๆฏๅๅญ็๏ผไธ x.store(1)
ๆฏไธฅๆ ผ็ๅ็ๅจ x.store(2)
ไนๅ๏ผx.store(2)
ไธฅๆ ผ็ๅ็ๅจ x.load()
ไนๅใ ๅผๅพไธๆ็ๆฏ๏ผ็บฟๆงไธ่ดๆงๅฏนๅ
จๅฑๆถ้็่ฆๆฑๆฏ้พไปฅๅฎ็ฐ็๏ผ่ฟไนๆฏไบบไปฌไธๆญ็ ็ฉถๆฏ่ฟไธชไธ่ดๆงๆดๅผฑๆกไปถไธๅ
ถไปไธ่ดๆง็็ฎๆณ็ๅๅ ใ
้กบๅบไธ่ดๆง๏ผๅๆ ท่ฆๆฑไปปไฝไธๆฌก่ฏปๆไฝ้ฝ่ฝ่ฏปๅฐๆฐๆฎๆ่ฟไธๆฌกๅๅ ฅ็ๆฐๆฎ๏ผไฝๆช่ฆๆฑไธๅ จๅฑๆถ้็้กบๅบไธ่ดใ
x.store(1) x.store(3) x.load()
T1 ---------+-----------+----------+----->
T2 ---------------+---------------------->
x.store(2)
ๆ่
x.store(1) x.store(3) x.load()
T1 ---------+-----------+----------+----->
T2 ------+------------------------------->
x.store(2)
ๅจ้กบๅบไธ่ดๆง็่ฆๆฑไธ๏ผx.load()
ๅฟ
้กป่ฏปๅฐๆ่ฟไธๆฌกๅๅ
ฅ็ๆฐๆฎ๏ผๅ ๆญค x.store(2)
ไธ x.store(1)
ๅนถๆ ไปปไฝๅ
ๅไฟ้๏ผๅณ ๅช่ฆ T2
็ x.store(2)
ๅ็ๅจ x.store(3)
ไนๅๅณๅฏใ
ๅ ๆไธ่ดๆง๏ผๅฎ็่ฆๆฑ่ฟไธๆญฅ้ไฝ๏ผๅช้่ฆๆๅ ๆๅ ณ็ณป็ๆไฝ้กบๅบๅพๅฐไฟ้๏ผ่้ๅ ๆๅ ณ็ณป็ๆไฝ้กบๅบๅไธๅ่ฆๆฑใ
a = 1 b = 2
T1 ----+-----------+---------------------------->
T2 ------+--------------------+--------+-------->
x.store(3) c = a + b y.load()
ๆ่
a = 1 b = 2
T1 ----+-----------+---------------------------->
T2 ------+--------------------+--------+-------->
x.store(3) y.load() c = a + b
ไบฆๆ่
b = 2 a = 1
T1 ----+-----------+---------------------------->
T2 ------+--------------------+--------+-------->
y.load() c = a + b x.store(3)
ไธ้ข็ปๅบ็ไธ็งไพๅญ้ฝๆฏๅฑไบๅ ๆไธ่ด็๏ผๅ ไธบๆดไธช่ฟ็จไธญ๏ผๅชๆ c
ๅฏน a
ๅ b
ไบง็ไพ่ต๏ผ่ x
ๅ y
ๅจๆญคไพๅญไธญ่กจ็ฐไธบๆฒกๆๅ
ณ็ณป๏ผไฝๅฎ้
ๆ
ๅตไธญๆไปฌ้่ฆๆด่ฏฆ็ป็ไฟกๆฏๆ่ฝ็กฎๅฎ x
ไธ y
็กฎๅฎๆ ๅ
ณ๏ผ
ๆ็ปไธ่ดๆง๏ผๆฏๆๅผฑ็ไธ่ดๆง่ฆๆฑ๏ผๅฎๅชไฟ้ๆไธชๆไฝๅจๆชๆฅ็ๆไธชๆถ้ด่็นไธไผ่ขซ่งๅฏๅฐ๏ผไฝๅนถๆช่ฆๆฑ่ขซ่งๅฏๅฐ็ๆถ้ดใๅ ๆญคๆไปฌ็่ณๅฏไปฅๅฏนๆญคๆกไปถ็จไฝๅ ๅผบ๏ผไพๅฆ่งๅฎๆไธชๆไฝ่ขซ่งๅฏๅฐ็ๆถ้ดๆปๆฏๆ็็ใๅฝ็ถ่ฟๅทฒ็ปไธๅจๆไปฌ็่ฎจ่ฎบ่ๅดไนๅ ไบใ
x.store(3) x.store(4)
T1 ----+-----------+-------------------------------------------->
T2 ---------+------------+--------------------+--------+-------->
x.read x.read() x.read() x.read()
ๅจไธ้ข็ๆ
ๅตไธญ๏ผๅฆๆๆไปฌๅ่ฎพ x ็ๅๅงๅผไธบ 0๏ผๅ T2
ไธญๅๆฌก x.read()
็ปๆๅฏ่ฝไฝไธ้ไบไปฅไธๆ
ๅต๏ผ
3 4 4 4 // x ็ๅๆไฝ่ขซๅพๅฟซ่งๅฏๅฐ
0 3 3 4 // x ็ๅๆไฝ่ขซ่งๅฏๅฐ็ๆถ้ดๅญๅจไธๅฎๅปถ่ฟ
0 0 0 4 // ๆๅไธๆฌก่ฏปๆไฝ่ฏปๅฐไบ x ็ๆ็ปๅผ๏ผไฝๆญคๅ็ๅๅๅนถๆช่งๅฏๅฐ
0 0 0 0 // ๅจๅฝๅๆถ้ดๆฎตๅ
x ็ๅๆไฝๅๆช่ขซ่งๅฏๅฐ๏ผ
// ไฝๆชๆฅๆไธชๆถ้ด็นไธไธๅฎ่ฝ่งๅฏๅฐ x ไธบ 4 ็ๆ
ๅต
ๅ
ๅญ้กบๅบ
ไธบไบ่ฟฝๆฑๆ่ด็ๆง่ฝ๏ผๅฎ็ฐๅ็งๅผบๅบฆ่ฆๆฑ็ไธ่ดๆง๏ผC++11 ไธบๅๅญๆไฝๅฎไนไบๅ
ญ็งไธๅ็ๅ
ๅญ้กบๅบ std::memory_order
็้้กน๏ผ่กจ่พพไบๅ็งๅค็บฟ็จ้ด็ๅๆญฅๆจกๅ๏ผ
ๅฎฝๆพๆจกๅ๏ผๅจๆญคๆจกๅไธ๏ผๅไธช็บฟ็จๅ
็ๅๅญๆไฝ้ฝๆฏ้กบๅบๆง่ก็๏ผไธๅ
่ฎธๆไปค้ๆ๏ผไฝไธๅ็บฟ็จ้ดๅๅญๆไฝ็้กบๅบๆฏไปปๆ็ใ็ฑปๅ้่ฟ std::memory_order_relaxed
ๆๅฎใๆไปฌๆฅ็ไธไธชไพๅญ๏ผ
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;
้ๆพ/ๆถ่ดนๆจกๅ๏ผๅจๆญคๆจกๅไธญ๏ผๆไปฌๅผๅง้ๅถ่ฟ็จ้ด็ๆไฝ้กบๅบ๏ผๅฆๆๆไธช็บฟ็จ้่ฆไฟฎๆนๆไธชๅผ๏ผไฝๅฆไธไธช็บฟ็จไผๅฏน่ฏฅๅผ็ๆๆฌกๆไฝไบง็ไพ่ต๏ผๅณๅ่
ไพ่ตๅ่
ใๅ
ทไฝ่่จ๏ผ็บฟ็จ A ๅฎๆไบไธๆฌกๅฏน x
็ๅๆไฝ๏ผ็บฟ็จ B
ไป
ไพ่ตๅ
ถไธญ็ฌฌไธๆฌก x
็ๅๆไฝ๏ผไธ x
็ๅไธคๆฌกๅ่กไธบๆ ๅ
ณ๏ผๅๅฝ A
ไธปๅจ x.release()
ๆถๅ๏ผๅณไฝฟ็จ std::memory_order_release
๏ผ๏ผ้้กน std::memory_order_consume
่ฝๅค็กฎไฟ B
ๅจ่ฐ็จ x.load()
ๆถๅ่งๅฏๅฐ A
ไธญ็ฌฌไธๆฌกๅฏน x
็ๅๆไฝใๆไปฌๆฅ็ไธไธชไพๅญ๏ผ
// ๅๅงๅไธบ nullptr ้ฒๆญข consumer ็บฟ็จไป้ๆ้่ฟ่ก่ฏปๅ
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::memory_order_release
ๅ่ทๅ std::memory_order_acquire
ไน้ด่งๅฎๆถๅบ๏ผๅณๅ็ๅจ้ๆพ๏ผrelease๏ผๆไฝไนๅ็ๆๆๅๆไฝ๏ผๅฏนๅ
ถไป็บฟ็จ็ไปปไฝ่ทๅ๏ผacquire๏ผๆไฝ้ฝๆฏๅฏ่ง็๏ผไบฆๅณๅ็้กบๅบ๏ผhappens-before๏ผใ
ๅฏไปฅ็ๅฐ๏ผstd::memory_order_release
็กฎไฟไบๅฎไนๅ็ๅๆไฝไธไผๅ็ๅจ้ๆพๆไฝไนๅ๏ผๆฏไธไธชๅๅ็ๅฑ้๏ผbackward๏ผ๏ผ่ std::memory_order_acquire
็กฎไฟไบๅฎไนๅ็ๅ่กไธบไธไผๅ็ๅจ่ฏฅ่ทๅๆไฝไนๅ๏ผๆฏไธไธชๅๅ็ๅฑ้๏ผforward๏ผใๅฏนไบ้้กน std::memory_order_acq_rel
่่จ๏ผๅ็ปๅไบ่ฟไธค่
็็น็น๏ผๅฏไธ็กฎๅฎไบไธไธชๅ
ๅญๅฑ้๏ผไฝฟๅพๅฝๅ็บฟ็จๅฏนๅ
ๅญ็่ฏปๅไธไผ่ขซ้ๆๅนถ่ถ่ฟๆญคๆไฝ็ๅๅ๏ผ
ๆไปฌๆฅ็ไธไธชไพๅญ๏ผ
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();
ๅจๆญคไพไธญๆไปฌไฝฟ็จไบ compare_exchange_strong
ๆฏ่พไบคๆขๅ่ฏญ๏ผCompare-and-swap primitive๏ผ๏ผๅฎๆไธไธชๆดๅผฑ็็ๆฌ๏ผๅณ compare_exchange_weak
๏ผๅฎๅ
่ฎธๅณไพฟไบคๆขๆๅ๏ผไนไป็ถ่ฟๅ false
ๅคฑ่ดฅใๅ
ถๅๅ ๆฏๅ ไธบๅจๆไบๅนณๅฐไธ่ๅๆ
้ๅฏผ่ด็๏ผๅ
ทไฝ่่จ๏ผๅฝ CPU ่ฟ่กไธไธๆๅๆขๆถ๏ผๅฆไธ็บฟ็จๅ ่ฝฝๅไธๅฐๅไบง็็ไธไธ่ดใ้คๆญคไนๅค๏ผcompare_exchange_strong
็ๆง่ฝๅฏ่ฝ็จๅทฎไบ compare_exchange_weak
๏ผไฝๅคง้จๅๆ
ๅตไธ๏ผ้ดไบๅ
ถไฝฟ็จ็ๅคๆๅบฆ่่จ๏ผcompare_exchange_weak
ๅบ่ฏฅ่ขซๆ้่่ใ
้กบๅบไธ่ดๆจกๅ๏ผๅจๆญคๆจกๅไธ๏ผๅๅญๆไฝๆปก่ถณ้กบๅบไธ่ดๆง๏ผ่ฟ่ๅฏ่ฝๅฏนๆง่ฝไบง็ๆ่ใๅฏๆพๅผ็้่ฟ std::memory_order_seq_cst
่ฟ่กๆๅฎใๆๅๆฅ็ไธไธชไพๅญ๏ผ
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;
่ฟไธชไพๅญไธ็ฌฌไธไธชๅฎฝๆพๆจกๅ็ไพๅญๆฌ่ดจไธๆฒกๆๅบๅซ๏ผไป
ไป
ๅชๆฏๅฐๅๅญๆไฝ็ๅ
ๅญ้กบๅบไฟฎๆนไธบไบ memory_order_seq_cst
๏ผๆๅ
ด่ถฃ็่ฏป่
ๅฏไปฅ่ช่ก็ผๅ็จๅบๆต้่ฟไธค็งไธๅๅ
ๅญ้กบๅบๅฏผ่ด็ๆง่ฝๅทฎๅผใ
Last updated