//--------------------------------------------------------------------------- #include #pragma hdrstop #include "EvryThng.h" //--------------------------------------------------------------------------- #pragma argsused // Программа из конспекта "Системное программное обеспечение" // Потоки, мьютексы и сигналы // стр. 69. eventPC.c */ /* Поддерживает два потока - производителя и потребителя. */ /* Производитель периодически создает буферные данные с контрольными */ /* суммами, или "блоки сообщений", сигнализирующие потребителю о готовности*/ /* сообщения. Поток потребителя отображает информацию в ответ на запрос.*/ #include #define DATA_SIZE 256 typedef struct msg_block_tag { /* Блок сообщения. */ volatile DWORD f_ready, f_stop; /* Флаги готовности и прекращения сообщений. */ volatile DWORD sequence; /* Порядковый номер блока сообщения. */ volatile DWORD nCons;//, nLost; time_t timestamp; HANDLE mguard; /* Мьютекс, защищающий структуру блока сообщения. */ HANDLE mready; /* Событие "Сообщение готово". */ DWORD checksum; /* Контрольная сумма сообщения. */ DWORD data [DATA_SIZE]; /* Содержимое сообщения. */ } MSG_BLOCK; MSG_BLOCK mblock={0,0,0,0,0}; DWORD WINAPI produce (void *); DWORD WINAPI consume (void *); void MessageFill (MSG_BLOCK *); void MessageDisplay (MSG_BLOCK *); DWORD _tmain (DWORD argc, LPTSTR argv []) { DWORD Status, ThId; HANDLE produce_h, consume_h; /* Инициализировать мьютекс и событие (автоматически сбрасываемое) в блоке сообщения. */ mblock.mguard = CreateMutex (NULL, FALSE, NULL); mblock.mready = CreateEvent (NULL, FALSE, FALSE, NULL); /* Создать потоки производителя и потребителя; ожидать их завершения.*/ /* ... Как в программе simplePC ... */ produce_h = CreateThread (NULL, 0, produce, NULL, 0, &ThId); consume_h = CreateThread (NULL, 0, consume, NULL, 0, &ThId); /* Ожидать завершения потоков производителя и потребителя. */ WaitForSingleObject (consume_h, INFINITE); WaitForSingleObject (produce_h, INFINITE); CloseHandle (mblock.mguard); CloseHandle (mblock.mready); _tprintf (_T ("Producer and consumer threads ended.\n")); _tprintf (_T ("Sent: %d, Received: %d, Lost: %d\n"), mblock.sequence, mblock.nCons, mblock.sequence - mblock.nCons); return 0; } DWORD WINAPI produce (void *arg) /* Поток производителя -- создание новых сообщений через случайные */ /* интервалы времени. */ { srand ((DWORD)time(NULL)); /* Создать начальное число для генератора случайных чисел. */ while (!mblock.f_stop) { /* Случайная задержка. */ Sleep (rand () / 10); /* Длительный период ожидания следующего сообщения. */ /* Получить и заполнить буфер. */ WaitForSingleObject (mblock.mguard, INFINITE); __try { if (!mblock.f_stop) { mblock.f_ready = 0; MessageFill (&mblock); mblock.f_ready = 1; mblock.sequence++; _tprintf (_T ("\nReady message # %d:"), mblock.sequence); SetEvent(mblock.mready); /* Сигнал "Сообщение готово". */ } } __finally { ReleaseMutex (mblock.mguard); } } return 0; } DWORD WINAPI consume (void *arg) { DWORD ShutDown = 0; CHAR command, extra; /* Принять ОЧЕРЕДНОЕ сообщение по запросу пользователя. */ while (!ShutDown) { /* Единственный поток, получающий доступ к стандартным устройствам ввода/вывода. */ _tprintf (_T ("\n** Enter 'c' for receive; 's' for stop: ")); _tscanf ("%c%c", &command, &extra); if (command == 's') { WaitForSingleObject (mblock.mguard, INFINITE); ShutDown = mblock.f_stop = 1; ReleaseMutex (mblock.mguard); return 1; } else if (command == 'c') { /* Получить новый буфер принимаемых сообщений. */ WaitForSingleObject (mblock.mready, INFINITE); WaitForSingleObject (mblock.mguard, INFINITE); __try { if (!mblock.f_ready) break;//_leave; /* Ожидать наступление события, указывающего на готовность сообщения. */ MessageDisplay (&mblock); mblock.nCons++; mblock.f_ready = 0; /* Новые готовые сообщения отсутствуют. */ } __finally { ReleaseMutex (mblock.mguard); } } else { _tprintf (_T ("Wrong command! Repeat.\n")); } } return 0; } void MessageFill (MSG_BLOCK *mblock) { /* Заполнить буфер сообщения содержимым, включая контрольную сумму и отметку времени. */ DWORD i; mblock->checksum = 0; for (i = 0; i < DATA_SIZE; i++) { mblock->data [i] = rand (); mblock->checksum ^= mblock->data [i]; } mblock->timestamp = time (NULL); return; } void MessageDisplay (MSG_BLOCK *mblock) { /* Отобразить буфер сообщения, отметку времени и контрольную сумму. */ DWORD i, tcheck = 0; for (i = 0; i < DATA_SIZE; i++) tcheck ^= mblock->data [i]; _tprintf (_T ("\nTime of generation message # %d: %s"), mblock->sequence, _tctime (&(mblock->timestamp))); _tprintf (_T ("First and last data strings: %x %x\n"), mblock->data [0], mblock->data [DATA_SIZE - 1]); if (tcheck == mblock->checksum) _tprintf (_T ("SUCCESS ->Checksum correct.\n")); else _tprintf (_T ("FAILURE ->Checksum wrong. Bad message.\n")); return; } //---------------------------------------------------------------------------