锁定自由并发示例;为什么不安全?

时间:2018-03-22 15:18:19

标签: c++ concurrency lock-free

我正在尝试学习C ++中的并发性,并且这样做我正在尝试查看哪些有效,哪些无效。下面的例子没有很好的设计,我知道有更好的方法来设计它,但我想知道为什么线程1和线程2似乎能够在共享数组中相互覆盖。我认为共享flag_atomic变量的操作与加载和释放语义在加载和写入共享idx_atomic索引之上和之下将阻止线程1和线程2检索相同的索引值,而不管idx_atomic操作记忆标签?

作为参考,我使用的是MSVC和x64。

#include <iostream>
#include <vector>
#include <atomic>
#include <thread>
#include <chrono>

using namespace std::chrono;    // for ""ms operator

const size_t c_size = 40;
std::vector<int> shared_array;
std::atomic<bool> sync_start_atomic = false;
std::atomic<bool> flag_atomic = false;
std::atomic<size_t> idx_atomic = 0;


void thread1_x() {
    bool expected_flag = false;
    size_t temp_idx = 0;
    while (!sync_start_atomic.load(std::memory_order_relaxed));
    for (size_t i = 0; i < (c_size / 2); ++i) {
        while (flag_atomic.compare_exchange_weak(expected_flag, true, std::memory_order_acq_rel, std::memory_order_acquire)) {
                expected_flag = false;
        }
        temp_idx = idx_atomic.load(std::memory_order_relaxed);
        idx_atomic.store((temp_idx + 1), std::memory_order_relaxed);
        flag_atomic.store(false, std::memory_order_release);
        shared_array[temp_idx] = i;

    }
}

void thread2_x() {
       bool expected_flag = false;
    size_t temp_idx = 0;
    while (!sync_start_atomic.load(std::memory_order_relaxed));
    for (size_t i = 0; i < (c_size / 2); ++i) {
        while (flag_atomic.compare_exchange_weak(expected_flag, true, std::memory_order_acq_rel, std::memory_order_acquire)) {
            expected_flag = false;
        }
        temp_idx = idx_atomic.load(std::memory_order_relaxed);
        idx_atomic.store((temp_idx + 1), std::memory_order_relaxed);
        flag_atomic.store(false, std::memory_order_release);
        shared_array[temp_idx] = i + 100;

    }
}

void main(){
    shared_array.reserve(c_size);
    shared_array.assign(c_size, 0);
    std::thread tn_1(thread1_x);
    std::thread tn_2(thread2_x);
    std::this_thread::sleep_for(60ms);
    sync_start_atomic.store(true, std::memory_order_relaxed);

    tn_1.join();
    tn_2.join();

    for (size_t i = 0; i < c_size; ++i) {
        std::cout << shared_array[i] << " ";
    }
    std::cout << "\n";
}

实际输出示例:

100,1,101,2,3,102,4,103,104,6,106,8,108,9,10,109,11,110,12,111,14,112,113,16 ,17,18,115,19,116,117,118,119,0,0,0,0,0,0,0,0。

预期输出示例:

0,100,101,102,103,104,105,106,107,108,109,110,111,112,113,1,2,114,3,115,4,5,6,7 ,8,9,10,11,12,13,14,15,116,16,117,17,118,18,119,19。

1 个答案:

答案 0 :(得分:1)

您的示例输出表明两个线程同时访问import pandas as pd import numpy as np chunksize = 50000 i=0 df = pd.read_excel("path/to/file.xlsx") for chunk in np.split(df, len(df) // chunksize): chunk.to_excel('path/to/destination/folder/file_{:02d}.xlsx'.format(i), index=True) i += 1 ,这表示您的idx_atomic循环出现问题。您正在使用的条件检查是向后的。 flag_atomic将返回compare_exchange_weak比较的结果 - 换句话说,当值更新时,它会返回flag_atomic == expected_flag。由于您希望在发生这种情况时退出循环,因此比较应为

true