Skip to content
Perestoronin Pavel edited this page Jan 11, 2021 · 1 revision

Паша

HANDLE mutex;
HANDLE can_read;
HANDLE can_write;
LONG waiting_writers = 0;
LONG waiting_readers = 0;
LONG active_readers = 0;
bool active_writer = false;

int value = 0;

void start_read(void) {
    InterlockedIncrement(&waiting_readers);
    if (active_writer || (WaitForSingleObject(can_write, 0) == WAIT_OBJECT_0 && waiting_writers)) 
        WaitForSingleObject(can_read, INFINITE);
    WaitForSingleObject(mutex, INFINITE);
    InterlockedDecrement(&waiting_readers);
    InterlockedIncrement(&active_readers);
    SetEvent(can_read);
    ReleaseMutex(mutex);
}

void stop_read(void) {
    InterlockedDecrement(&active_readers);
    if (active_readers == 0) {
        ResetEvent(can_read);
        SetEvent(can_write);
    }
}

DWORD WINAPI run_reader(CONST LPVOID lpParams) {
    int index = (int)lpParams;
    int sleep_time;
    srand(time(NULL) + index);
    for (size_t i = 0; i < 7; i++) {
        sleep_time = 300 + rand() % 4000;
        Sleep(sleep_time);
        start_read();
        printf("  Reader #%ld read:  %5ld (slept %4d ms)\n", index, value, sleep_time);
        stop_read();
    }
    return 0;
}

void start_write(void) {
    InterlockedIncrement(&waiting_writers);
    if (active_writer || active_readers > 0) 
        WaitForSingleObject(can_write, INFINITE);
    InterlockedDecrement(&waiting_writers);
    active_writer = true;
}

void stop_write(void) {
    active_writer = false;
    if (waiting_readers) 
        SetEvent(can_read);
    else 
        SetEvent(can_write);
}

DWORD WINAPI run_writer(CONST LPVOID lpParams) {
    int index = (int)lpParams;
    int sleep_time;
    srand(time(NULL) + index + 5);
    for (int i = 0; i < 8; ++i) {
        sleep_time = 300 + rand() % 4000;
        Sleep(sleep_time);
        start_write();
        ++value;
        printf("  Writer #%ld write: %5ld (slept %4d ms)\n", index, value, sleep_time);
        stop_write();
    }
    return 0;
}

int main(void) {
    setbuf(stdout, NULL);
    HANDLE readers_threads[5];
    HANDLE writers_threads[3];
    if ((mutex = CreateMutex(NULL, FALSE, NULL)) == NULL) {
        perror("Failed call of CreateMutex");
        return -1;
    }
    if ((can_read = CreateEvent(NULL, FALSE, FALSE, NULL)) == NULL 
            || (can_write = CreateEvent(NULL, FALSE, FALSE, NULL)) == NULL) {
        perror("Failed call of CreateEvent");
        return -1;
    }
    for (int i = 0; i < 5; ++i) 
        if ((readers_threads[i] = CreateThread(NULL, 0, run_reader, (LPVOID)i, 0, NULL)) == NULL) {
            perror("Failed call of CreateThread");
            return -1;
    }
    for (int i = 0; i < 3; i++) 
        if ((writers_threads[i] = CreateThread(NULL, 0, run_writer, (LPVOID)i, 0, NULL)) == NULL) {
            perror("Failed call of CreateThread");
            return -1;
        }

    WaitForMultipleObjects(5, readers_threads, TRUE, INFINITE);
    WaitForMultipleObjects(3, writers_threads, TRUE, INFINITE);
    CloseHandle(mutex);
    CloseHandle(can_read);
    CloseHandle(can_write);

    return 0;
}

Clone this wiki locally