Я делаю своего рода упражнение на атомарности C ++.
Я написал следующий код, в котором я запускаю 2 потока чтения, которые читают некоторые структурированные данные на основе счетчика готовности, который увеличивается основным потоком на 2 каждый раз, когда он обновляет данные. Каждый флаг считывателя один раз ненулевой читает данные и уменьшает счетчик на 1.
Код
#include <atomic>
#include <thread>
#include <iostream>
#include <functional>
#include <chrono>
struct Foo
{
int a;
int b;
int c;
};
int main()
{
unsigned long writeCnt { 0 };
std::atomic<int> dataReady {0};
//Shared data
Foo data {0, 0, 0};
//Readers accumulate data here
Foo dataBuf[2][1000];
//Reader threads
std::thread threads[2];
//A pointer to a buffer assigned to a reader
Foo (*curBuf)[1000] = dataBuf;
//Thread's ID
int threadNum { 0 };
//Starting readers
for (auto & item : threads)
{
item = std::thread(std::bind([&dataReady,&data](Foo * buf, const int threadNum)
{
unsigned long readCnt { 0 };
while (readCnt < 1000)
{
auto ready = dataReady.load(std::memory_order_relaxed);
std::cout << "Thread #" << threadNum << " ready " << ready << " read cnt " << readCnt <<std::endl;
if(ready > 0)
{
std::atomic_thread_fence(std::memory_order_acquire);
buf[readCnt].a = data.a;
buf[readCnt].b = data.b;
buf[readCnt].c = data.c;
std::atomic_thread_fence(std::memory_order_release);
dataReady.store(ready - 1, std::memory_order_relaxed);
++readCnt;
}
else
{
continue;
}
}
},*(curBuf++),threadNum++));
}
//Writer loop
while (writeCnt < 1000)
{
auto ready = dataReady.load(std::memory_order_relaxed);
std::cout << "Main thread ready " << ready << " write cnt " << writeCnt << std::endl;
if(ready == 0)
{
std::atomic_thread_fence(std::memory_order_acquire);
data.a = writeCnt;
data.b = writeCnt;
data.c = writeCnt;
std::atomic_thread_fence(std::memory_order_release);
dataReady.store(2, std::memory_order_relaxed);
++writeCnt;
}
else
{
continue;
}
}
//Joining readers
for(auto & item : threads)
{
if(item.joinable())
{
item.join();
}
}
//Print accumulated data
for(const auto & buffer : dataBuf)
{
for(const auto & item : buffer)
{
std::cout << item.a << " " << item.b << " " << item.c << std::endl;
}
}}
На данный момент не имеет значения, что возможно только один поток дважды читает обновленные данные. Я волнуюсь о writeCnt
останавливается около 730 или около того, пока читатели заканчивают чтение.
Это неправильное поведение вызвано переупорядочением памяти и почему после добавления ограждений потоков?
Что мне здесь не хватает?
Задача ещё не решена.
Других решений пока нет …