how to update a variable in contiguous memory atomicly

  atomic, c++, memory-alignment

I have a struct with multi variables packed which is not aligned.Then I make an array of the struct and set up a reader thread and a writer thread to update the variable concurrently.I find error value which only half of the variable is updated from output.I guess this is caused by one variable lay in two cache lines.Change the variable to atomic doesn’t solve the problem.So,is there a way to solve this without memory aligned?

#include <thread>
#include <atomic>
#include <iostream>
#include <mutex>
#include <stdalign.h>

#pragma pack(1)
struct Foo {
    uint64_t key;
    uint64_t key2;
    uint64_t key3;
    uint32_t key4;
    uint64_t key5;
};
#pragma pack()


const int block_size = 10;

uint64_t keys[10];

void printEle(const Foo* ele) {
    std::cout << "Key " << ele->key
              << " key2 " << ele->key2
              << " key3 " << ele->key3
              << " key5 " << ele->key5 << std::endl;
}


void reader(Foo* list) {
    for (int i = 0; i < 1000000; ++i) {
        for (int j = 0; j < block_size; ++j) {
            Foo* ele = reinterpret_cast<Foo*>(list + j);
            printEle(ele);
        }
    }
}

void writer(Foo* list) {
    for (int i = 0; i < 1000000; ++i) {
        for (int j = 0; j < block_size; ++j) {
            Foo* ele = reinterpret_cast<Foo*>(list + j);
            if (i % 2 == 0) {
                ele->key = keys[j];
                ele->key2 =  keys[j];
                ele->key3 = keys[j];
                ele->key5 = keys[j];
            } else {
                ele->key = j;
                ele->key2 = j;
                ele->key3 = j;
                ele->key5 = j;
            }
        }
    }
}

void test() {
    keys[0]= 1556273083026830079;
    keys[1]= 6541630416163430395;
    keys[2]= 2310622570815837826;
    keys[3]= 12643974306886634761;
    keys[4]= 15393333677141345392;
    keys[5]= 3591765785331799809;
    keys[6]= 5404586990109662840;
    keys[7]= 1376395845958874653;
    keys[8]= 7620513273959825252;
    keys[9]= 16620834775579010287;


    Foo* list = new Foo[block_size];
    for (int i = 0; i < block_size; ++i) {
        uint64_t k = keys[i];
        Foo* ele = reinterpret_cast<Foo*>(list + i);
        ele->key = k;
        ele->key2 = k;
        ele->key3 = k;
        ele->key4 = 707406378;
        ele->key5 = k;
    }
    std::thread write(writer, list);
    std::thread read(reader, list);
    read.join();
    write.join();
}

int main(int argc, char* argv[]) {
    std::cout << "Size " << sizeof(Foo) << std::endl;
    test();
    std::cout << "done." << std::endl;
    return 0;
}

Source: Windows Questions C++

LEAVE A COMMENT