MultiThreading производитель / потребитель

Я пишу основной код потоков производителя / потребителя. У меня большая часть работы, но у меня проблема с rand (). Или, может быть, мои проблемы глубже, чем rand (), а rand — это только верхушка айсберга. Я не хочу делать что-то слишком сложное, (ни один из работоспособного или ждать).

У меня есть глобальный deque целых чисел, который действует как буфер. Я разрешаю пользователю вводить размер и лимит времени выполнения.
Я делаю счетчик статической глобальной переменной.
это мой продюсер

DWORD WINAPI producer(LPVOID n)
{
cout << "\nPRODUCER:The producer is running right now" << endl;
int size = (int)n;
int num = rand()%10;// this is for making item.
while (buffer.size() > size)
{
}

buffer.push_back(num);
counter++;
return (DWORD)n;

}

это мой потребитель

 DWORD WINAPI consumer(LPVOID n)
{

cout << "\nCONSUMER:The consumer is running right now" << endl;
while (buffer.empty())
{ }
int item= buffer.front();
cout << "\nCONSUMER:The consumer ate" << item << endl;
counter++;

return (DWORD)n;}

в основном

 while (counter < l)
{
hThreads[0] = CreateThread(NULL, 0, producer, (LPVOID)s, NULL, &id[0]);
hThreads[1] = CreateThread(NULL, 0, consumer, (LPVOID)l, NULL, &id[1]);

waiter = WaitForMultipleObjects(MAX_THREADS, hThreads, TRUE, INFINITE);
}
for (int i = 0; i < MAX_THREADS; i++) {
CloseHandle(hThreads[i]);
}

Мой вывод такой:
введите описание изображения здесь

Так что он генерирует только 1 каждый раз. Сранд тоже не работал. Но он работает правильное количество раз.

РЕДАКТИРОВАТЬ—
Поэтому я установил производителя и потребителя, чтобы иметь дело с состоянием гонки:

  DWORD WINAPI producer(LPVOID s)
{
WaitForSingleObject(Empty, INFINITE);
WaitForSingleObject(Mutex, INFINITE);
cout << "\nPRODUCER...." << endl;
int size = (int)s;
srand(size);
int in = rand() % 10;
cout << "THIS IS IN:::" << in << endl;
while (buffer.size() == size)
{
ReleaseMutex(Mutex);
}
buffer.push_back(in);
counter++;
cout << "\nThe producer produces " << buffer.front() << endl;
ReleaseMutex(Mutex);
ReleaseSemaphore(Full, 1, NULL);

return (DWORD)s;
}DWORD WINAPI consumer(LPVOID l)
{
WaitForSingleObject(Full, INFINITE);
WaitForSingleObject(Mutex, INFINITE);
cout << "\nCONSUMER...." << endl;
while (buffer.empty())
{
ReleaseMutex(Mutex);

}
int out = buffer.front();
counter++;
ReleaseMutex(Mutex);
ReleaseSemaphore(Empty, 1, NULL);
return (DWORD)l;
}

НО случайная вещь все еще продолжает действовать. Он продолжает выдавать только один номер снова и снова (даже при посеве).

-1

Решение

Да, не имеет смысла создавать (и уничтожать) поток, чтобы создавать или обрабатывать только одно число — дополнительные издержки просто не стоят. Плюс в вашем коде (как есть) есть некоторые очевидные ошибки или неправильные представления. Это:

  • В основном потоке вы создаете рабочие потоки (в этом цикле while () {}), но уничтожаете их только один раз в конце, то есть уничтожаете только дескрипторы, созданные в последнем цикле.
  • Как отмечалось в моем сообщении, srand () вызывается для каждого генерируемого числа, и всегда с одним и тем же начальным начальным числом, поэтому нормально получать одинаковые числа.
  • Цикл while (), проверяющий, пуст ли буфер или нет, не имеет смысла и не должен освобождать Mutex.
  • Операции на counter переменные, вероятно, неправильно. Поток как производителя, так и потребителя увеличивает его, а основной поток использует его, чтобы определить, сколько чисел нужно сгенерировать / напечатать.
  • В вашем исходном фрагменте кода, counter это глобальная переменная, в которой работают несколько потоков, поэтому вы должны читать или изменять ее потокобезопасным способом, а не так. Вы должны использовать некоторый механизм блокировки, такой как критический раздел или блокированный доступ к переменным.

Мое предложение было бы создать один поток производителя (генерация всех чисел) и один потребительский поток (печать всех чисел), передаваемых через буфер. Для этого вам понадобятся следующие элементы (большинство из них вы уже реализовали):

  • «Полный» семафор, считающий числа в буфере, изначально 0.
  • Дополнительный «пустой» семафор, считающий пустые элементы в буфере, изначально установлен на размер буфера. «Сумма» этих семафоров всегда должна быть равна размеру буфера.
  • Мьютекс (или критическая секция), используемый для доступа к буферу.
  • Глобальная переменная, используемая для сообщения потокам о выходе.

Я публикую некоторые примеры кода ниже. Не уверен, что они работают, возможно, вам придется пересмотреть или отладить их, но это просто для демонстрации концепции:

// Global
#define MAX_BUF 5
BOOL bExit = FALSE;

// Main Thread
Empty = CreateSemaphore(NULL, MAX_BUF, MAX_BUF, NULL);
Full = CreateSemaphore(NULL, 0, MAX_BUF, NULL);
.
.
hThreads[0] = CreateThread(NULL, 0, producer, (LPVOID)l, NULL, &id[0]);
hThreads[1] = CreateThread(NULL, 0, consumer, (LPVOID)l, NULL, &id[1]);
waiter = WaitForMultipleObjects(MAX_THREADS, hThreads, TRUE, INFINITE);

for (int i = 0; i < MAX_THREADS; i++)
CloseHandle(hThreads[i]);DWORD WINAPI producer(LPVOID nCount)
{
int nItems = (int)nCount;
// Initialize rand() seed - each run will be generating a different sequence
srand(GetTickCount()); // May need to AND GetTickCount() with RAND_MAX ???
// Generate nCount numbers
for (int i = 0; i < nItems; i++)
{
if (bExit) return 9; // Aborted
WaitForSingleObject(Empty, INFINITE); // Wait until at least one item empty
// Lock the buffer and add an item
WaitForSingleObject(Mutex, INFINITE); // Could be EnterCriticalSection() instead
if (buffer.size() >= MAX_BUF)
{
cout << "\nInternal Error: Buffer-full Check Failed!" << endl;
bExit = TRUE; // Tell all threads to exit
ReleaseMutex(Mutex);
return 1; // Exit with Error
}
int in = rand() % 10;
buffer.push_back(in);
cout << "The Producer generated: " << in << endl;
ReleaseMutex(Mutex); // Could be LeaveCriticalSection() instead
ReleaseSemaphore(Full, 1, NULL); // 1 item added, update semaphore
}
cout << "\nThe PRODUCER produced " << nItems << " items." << endl;
return 0; // OK
}

DWORD WINAPI consumer(LPVOID nCount)
{
int nItems = (int)nCount;
// Generate nCount numbers
for (int i = 0; i < nItems; i++)
{
if (bExit) return 9; // Aborted
WaitForSingleObject(Full, INFINITE); // Wait until at least one item in buffer
// Lock the buffer and get an item
WaitForSingleObject(Mutex, INFINITE); // Could be EnterCriticalSection() instead
if (buffer.empty())
{
cout << "\nInternal Error: Buffer-empty Check Failed!" << endl;
bExit = TRUE; // Tell all threads to exit
ReleaseMutex(Mutex);
return 2; // Exit with Error
}
int out = buffer.front();
buffer.erase(buffer.begin()); // Remove item from the list
cout << "The Consumer ate: " << out << endl;
ReleaseMutex(Mutex);  // Could be LeaveCriticalSection() instead
ReleaseSemaphore(Empty, 1, NULL); // 1 item removed, update semaphore
}
cout << "\nThe CONSUMER consumed " << nItems << " items." << endl;
return 0; // OK
}

Заметки:

  • bExit переменная является глобальной и доступна / модифицируется более чем одним потоком, но так как это всегда выполняется в критической секции (блокировка мьютекса), нет необходимости использовать другую или доступ к блокированной переменной.
  • Диагностические сообщения (например, cout << "The Consumer ate: " << out << endl;) или любой другой вид «обработки» этих данных (или «работы» с ними) мог быть помещен после выпуская объекты. Это было бы более эффективно, выпуская объекты ранее другому потоку (ам). Я сделал это таким образом, чтобы лучше проиллюстрировать последовательность событий в ваших тестах.
  • Если вы установите MAX_BUF равным 1, числа должны генерироваться / печататься по одному за раз, иначе это невозможно определить, но произведенные элементы за вычетом использованных элементов, конечно, никогда не должны превышать размер буфера.
0

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]