๐Ÿคฃ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 ๅฏไปฅ่งฃๅ†ณไธŠ้ขๅ‡บ็Žฐ็š„ๅนถๅ‘่ฏปๅ†™็š„้—ฎ้ข˜๏ผŒไฝ†ไบ’ๆ–ฅ้”ๆ˜ฏๆ“ไฝœ็ณป็ปŸ็บง็š„ๅŠŸ่ƒฝ๏ผŒ ่ฟ™ๆ˜ฏๅ› ไธบไธ€ไธชไบ’ๆ–ฅ้”็š„ๅฎž็Žฐ้€šๅธธๅŒ…ๅซไธคๆกๅŸบๆœฌๅŽŸ็†๏ผš

  1. ๆไพ›็บฟ็จ‹้—ด่‡ชๅŠจ็š„็Šถๆ€่ฝฌๆข๏ผŒๅณใ€Ž้”ไฝใ€่ฟ™ไธช็Šถๆ€

  2. ไฟ้šœๅœจไบ’ๆ–ฅ้”ๆ“ไฝœๆœŸ้—ด๏ผŒๆ‰€ๆ“ไฝœๅ˜้‡็š„ๅ†…ๅญ˜ไธŽไธด็•ŒๅŒบๅค–่ฟ›่กŒ้š”็ฆป

่ฟ™ๆ˜ฏไธ€็ป„้žๅธธๅผบ็š„ๅŒๆญฅๆกไปถ๏ผŒๆขๅฅ่ฏ่ฏดๅฝ“ๆœ€็ปˆ็ผ–่ฏ‘ไธบ 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