Синхронизация в Windows C ++

Мне нужно реализовать следующую систему: 1 писатель и 3 читателя во взаимном исключении, но 3 читателя могут читать одновременно. Писатель записывает в общую переменную, называемую dato, случайное число, читатели должны вывести его на консоль. Ожидаемый результат: Я написал: 7; Читаю: 7; Читаю: 7; Я прочитал: 7 Я написал: 1; Читаю: 1; Читаю: 1; Я прочитал: 1 Я написал: 9; Читаю: 9; Читаю: 9; Я прочитал: 9

Я использовал два unique_lock на мьютексе m и две condition_variables: cv1 для читателей (они могут читать, только если писатель уже написал) и cv2 для писателя (он может писать, только если все читатели прочитали).

Чтобы гарантировать параллельное чтение, после ожидания я разблокировал и беру блокировку после инструкции cout. Я думаю, что этот писатель не мог взять блокировку, потому что, когда они читают, он находится в ожидании, а условие opDone == 3 недействительно.

Вместо этого вывод: Я написал: 1 Я прочитал: 1 Я прочитал: Я прочитал: 1 Я прочитал: 1 Я прочитал: 1 1

Это код:

// nreader1writer.cpp : Defines the entry point for the console application.

#include "stdafx.h"

condition_variable cv1, cv2;
mutex m;
volatile atomic_int opDone = 0;
volatile atomic_bool iWrote = false;
volatile atomic_bool flag = false;

volatile atomic_int dato;

void writer();
void reader();

int _tmain()
{
    thread t1(reader);
    thread t2(reader);
    thread t3(reader);
    thread t4(writer);

    t1.join();
    t2.join();
    t3.join();
    t4.join();
    return 0;
}

void writer() {
    unique_lock <mutex> ulw (m, defer_lock);
    while (opDone.load() != 3); //In this way, writer starts just when all readers are already waiting 
    ulw.lock();
    opDone.store(0);
    iWrote.store(false);

    while (1) { 
        dato.store( (int) rand()%10);
        cout << "I wrote: " << dato.load() << endl;
        iWrote.store(true);
        cv1.notify_all();
        cv2.wait(ulw, []() {
            return (opDone.load() == 3);
        });
        opDone.store(0);
        iWrote.store(false);
    }
}

void reader() {
    unique_lock <mutex> ulr (m, defer_lock);
    ulr.lock();
    opDone.fetch_add(1);

    while (1) {
        cv1.wait(ulr, []() {
            return (iWrote.load() == true && opDone.load() < 3);
        });
        ulr.unlock();
        cout << "I read: " << dato << endl;
        ulr.lock();
        opDone.fetch_add(1);
        cv2.notify_one();
    }
}

Код отлично работает, если я не разблокирую () перед чтением, но в этом случае операции чтения не параллельны. Есть предложения?


person Joe22    schedule 05.09.2015    source источник


Ответы (1)


Взгляните на инициализацию ваших атомарных переменных. Например, Clang выводит предупреждение.

volatile atomic_int opDone = 0;
// error: copying variable of type 'atomic_int' (aka '__atomic_base') invokes deleted constructor

В рабочем проекте (текущий N4527) говорится следующее в §8.5.15.

Инициализация, которая происходит в форме = скобки-или-равно-инициализатора или условия (6.4), а также при передаче аргументов, возврате функции, выдаче исключения (15.1), обработка исключения (15.3) и инициализация агрегированного члена (8.5.1), называется инициализацией копирования. [Примечание: инициализация копирования может вызвать перемещение (12.8). - конец примечания]

Причина в том, что вы не можете скопировать атомикс. Все загрузки и сохранения должны происходить с явным вызовом. Исправление следующим образом должно решить проблему:

static atomic_int opDone(0);
person HelloWorld    schedule 05.09.2015