Я пишу основной код потоков производителя / потребителя. У меня большая часть работы, но у меня проблема с 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;
}
НО случайная вещь все еще продолжает действовать. Он продолжает выдавать только один номер снова и снова (даже при посеве).
Да, не имеет смысла создавать (и уничтожать) поток, чтобы создавать или обрабатывать только одно число — дополнительные издержки просто не стоят. Плюс в вашем коде (как есть) есть некоторые очевидные ошибки или неправильные представления. Это:
counter
переменные, вероятно, неправильно. Поток как производителя, так и потребителя увеличивает его, а основной поток использует его, чтобы определить, сколько чисел нужно сгенерировать / напечатать.counter
это глобальная переменная, в которой работают несколько потоков, поэтому вы должны читать или изменять ее потокобезопасным способом, а не так. Вы должны использовать некоторый механизм блокировки, такой как критический раздел или блокированный доступ к переменным.Мое предложение было бы создать один поток производителя (генерация всех чисел) и один потребительский поток (печать всех чисел), передаваемых через буфер. Для этого вам понадобятся следующие элементы (большинство из них вы уже реализовали):
Я публикую некоторые примеры кода ниже. Не уверен, что они работают, возможно, вам придется пересмотреть или отладить их, но это просто для демонстрации концепции:
// 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;
) или любой другой вид «обработки» этих данных (или «работы» с ними) мог быть помещен после выпуская объекты. Это было бы более эффективно, выпуская объекты ранее другому потоку (ам). Я сделал это таким образом, чтобы лучше проиллюстрировать последовательность событий в ваших тестах.Других решений пока нет …