Модель Производитель-Потребитель - PullRequest
1 голос
/ 28 апреля 2020

Я пытаюсь смоделировать модель производителя-потребителя о многопоточности.

Мы предполагаем, что нужно соблюдать три правила:

  1. Производитель не может добавить продукт в корзину, когда В ведре полно продуктов.
  2. Потребитель не может получить продукт из ведра, когда ведро пусто.
  3. Производство и потребление не могут осуществляться одновременно. Другими словами, эти два действия являются асинхронными.

Теперь, что у меня есть:

  1. a int переменная для хранения количества продуктов в корзине
  2. a const int переменная для емкости сегмента, которая в моем коде оценивается как 5.
  3. a int переменная для мьютекса, начальное значение 1
  4. a vector<HANDLE> переменная для приостановленного дескриптора, и будет функция планирования этих приостановленных потоков.

Результат: иногда он работает нормально, но иногда становится тупиком. Код и результаты следующие:

код:

#include <iostream>
#include <Windows.h>
#include <vector>

using namespace std;

// the count of product, the initial value is 0
int product_count = 0;

const int product_capacity = 5;

int mutex = 1;

vector<HANDLE> suspendedHandleVector;

HANDLE GetCurrentRealHandle() {
    HANDLE realHandle = 0;
    return OpenThread(THREAD_ALL_ACCESS, TRUE, GetCurrentThreadId());
}

void ThreadScheduling() {
    if (suspendedHandleVector.size() > 0) {
        HANDLE handle = suspendedHandleVector[0];
        suspendedHandleVector.erase(suspendedHandleVector.begin());
        ResumeThread(handle);
    }
}

void P() {
    --mutex;
    if (mutex < 0) {
        auto handle = GetCurrentRealHandle();
        suspendedHandleVector.push_back(handle);
        SuspendThread(handle);
    }
}

void V() {
    ++mutex;
    if (mutex >= 0) {
        ThreadScheduling();
    }
}

DWORD WINAPI ProducerThread(LPVOID param) {
    while (true) {
        P();
        if (product_count == product_capacity) {
            V();
            continue;
        }
        ++product_count;
        cout << "I'm producer, and there are " << product_count << " products now" << endl;
        V();
        Sleep(100);
    }
    return 0;
}

DWORD WINAPI ConsumerThread(LPVOID param) {
    while (true) {
        P();
        if (product_count == 0) {
            V();
            continue;
        }
        --product_count;
        cout << "I'm consumer, and there are " << product_count << " products rest now" << endl;
        V();
        Sleep(150);
    }
    return 0;
}

void main() {
    auto producer_handle = CreateThread(nullptr, 0, ProducerThread, nullptr, 0, nullptr);
    auto consumer_handle = CreateThread(nullptr, 0, ConsumerThread, nullptr, 0, nullptr);
    while (true) {
        cout << suspendedHandleVector.size() << endl; // This is for debugging
        Sleep(100);
    }
}

результат, когда он работает, как ожидалось:

0
I'm producer, and there are 1 products now
I'm consumer, and there are 0 products rest now
0
I'm producer, and there are 1 products now
I'm consumer, and there are 0 products rest now
0
I'm producer, and there are 1 products now
0
I'm consumer, and there are 0 products rest now
I'm producer, and there are 1 products now
0
I'm producer, and there are 2 products now
I'm consumer, and there are 1 products rest now

И это ожидаемая бесконечность l oop. Количество продуктов будет равно 4 и 5, потому что я заставляю производителя спать немного больше времени, чем потребителя.

Но вот неожиданный результат:

I'm producer, and there are 5 products now
I'm consumer, and there are 4 products rest now
0
I'm consumer, and there are 4 products rest now
I'm producer, and there are 5 products now
0
0
I'm consumer, and there are 4 products rest now
I'm producer, and there are 5 products now
0
2
2
2
2
2
2

Как мы видим, размер подвешенного вектора резьбы достиг 2 из 0, что не равно 1.

Это просто совпадение, когда два потока были разбужены в то же самое время, когда были конфликтом?

Я считаю, что что-то не так с моим кодом, который нуждается в вашей помощи.

Я также получил проблема во время тестирования: как получить поток и сохранить его в векторе.

Я не уверен, что для этого нужно использовать OpenThread. Мой курс попросил меня использовать системный вызов, поэтому я не включил thread headfile.

Спасибо за вашу помощь!

1 Ответ

0 голосов
/ 28 апреля 2020

В проблеме «производитель-потребитель» есть три участника: производитель, потребитель и буфер, используемый для хранения полученных данных. Производитель и потребитель обычно живут в одном или нескольких потоках (многопользовательский, однопользовательский, однопользовательский, многопользовательский, многопользовательский, многопользовательский).

Теперь этот шаблон очень используется, потому что он один из способ избежать явной синхронизации.

Как я уже сказал, потребитель и потребитель обычно живут в одном или нескольких потоках. Буфер обычно представляет собой синхронизированную очередь (может быть как заблокированной, так и без блокировки).

Очень короткий фрагмент:


SyncronizedQueue queue;

void consumer()
{
  while(1) {
    queue.push(std::rand());
  }
}

void producer()
{
    while(1)
    {
      auto product = queue.pop();   // blocks until there are elements in the 
    }
}

void main()
{
  std::thread producerThread{producer};
  std::thread consumerThread{consumer};

  producerThread.join();
  consumerThread.join();
}

Таким образом, задача состоит в том, чтобы написать очередь так, чтобы безопасные push элементы и разблокировка pop при нажатии на новый элемент.

Один простой способ реализовать это использовать условные переменные, чтобы функция pop блокировалась до тех пор, пока не будет выполнено условие, а пу sh метод добавить элемент в очередь и запустить условие.

...