Синхронизация потоков с помощью критических секций через общую память - C (СИ)
Формулировка задачи:
С 1 потоком работает нормально, а вот с 2 и более нет. Синхронизация с помощью критических секций через общую память. Почему-то зацикливается в while... Вот код:
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <conio.h> #include <windows.h> #include <locale.h> #include <io.h> #define BUFFER_SIZE 16384 //Размер буфера #define BUFFER_TYPE unsigned char CRITICAL_SECTION rdf, sdf, wrt, CMP; LARGE_INTEGER StockFileSize; unsigned long Flag = 1; long FlagUse = 1; int amnt; int n = 2;//количество нитей bool END = 1; long long sz = 0; long long szz, of, bsz; int q; OVERLAPPED StockOver; struct sRead //структура для чтения исходного файла { unsigned char buf[BUFFER_SIZE]; DWORD count; }; sRead forRead[256]; struct sSend //структура для передачи в нить { unsigned BUFFER_TYPE buf[BUFFER_SIZE]; DWORD count; DWORD thrd; DWORD amount; DWORD fsize; }; sSend forSend[256]; struct sWrite //структура для записи в новый файл { unsigned BUFFER_TYPE buf[BUFFER_SIZE]; DWORD count; DWORD thrd; DWORD amount; }; sWrite forWrite[256]; void Error(char err[]) { printf("%s", err); _getch(); exit(-1); } DWORD WINAPI newThread(LPVOID lp) { HANDLE hModFile; OVERLAPPED ModOver; DWORD dwCountBytes; LARGE_INTEGER ModFileSize; int name; ModOver.hEvent = CreateEvent(NULL, FALSE, TRUE, NULL); ModOver.Offset = 0; ModOver.OffsetHigh = 0; hModFile = CreateFile("desh.txt", GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL); if (hModFile == NULL) Error("Закодированный файл не создан"); int nmb = (int)lp; //получаем номер нити long cmp = 0; //переменная для проверки бита флага, соответствующего номеру нити cmp = 1 << (nmb); int k = 1; while (END) { if ((Flag&cmp) != 1) { while (FlagUse) Sleep(10); for (int i = 0; i < BUFFER_SIZE; i += 2) { EnterCriticalSection(&sdf); EnterCriticalSection(&wrt); char с = forSend[nmb].buf[i]; forSend[nmb].buf[i] = forSend[nmb].buf[i + 1]; forSend[nmb].buf[i + 1] = с; forWrite[nmb].buf[i] = forSend[nmb].buf[i]; forWrite[nmb].buf[i + 1] = forSend[nmb].buf[i + 1]; LeaveCriticalSection(&wrt); LeaveCriticalSection(&sdf); } of = ModOver.Offset + BUFFER_SIZE; if ((of) > StockFileSize.LowPart) { EnterCriticalSection(&wrt); bsz = BUFFER_SIZE - sz; WriteFile(hModFile, forWrite[nmb].buf, bsz, &dwCountBytes, &ModOver); GetOverlappedResult(hModFile, &ModOver, &forWrite[nmb].count, TRUE); ModOver.Offset += bsz; LeaveCriticalSection(&wrt); } else { EnterCriticalSection(&wrt); WriteFile(hModFile, forWrite[nmb].buf, BUFFER_SIZE, &dwCountBytes, &ModOver); GetOverlappedResult(hModFile, &ModOver, &forWrite[nmb].count, TRUE); ModOver.Offset += BUFFER_SIZE; LeaveCriticalSection(&wrt); } if (k != 1) WaitForSingleObject(ModOver.hEvent, INFINITE); else k++; Flag = Flag | cmp; FlagUse = 0; } } CloseHandle(hModFile); return(0); } int main(int argc, char * argv[]) { setlocale(LC_CTYPE, "Russian"); HANDLE hThread[32]; HANDLE hStockFile; HANDLE hModFile; DWORD dwCountBytes; DWORD dwNextSize; DWORD dwThreadID; char StockFileName[30]; char ModFileName[30]; LONGLONG StockNRecord = 1; OVERLAPPED ModOver; InitializeCriticalSection(&rdf); InitializeCriticalSection(&sdf); InitializeCriticalSection(&wrt); long tmp = 0; long flg = 0; //переменная для хранения значения флага, которое появляется в переменной Flag после обработки информации всеми нитями for (int i = 0; i < n; i++) { tmp = 1 << i; flg = flg | tmp; } hStockFile = CreateFile("inf.txt", GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL); if (hStockFile == NULL)//если исходный файл не открылся Error("Исходный файл не найден"); StockFileSize.HighPart = 0; StockFileSize.LowPart = GetFileSize(hStockFile, (LPDWORD)StockFileSize.HighPart);//размер файла StockOver.hEvent = CreateEvent(NULL, FALSE, TRUE, NULL); StockOver.Offset = 0; StockOver.OffsetHigh = 0; StockNRecord = StockFileSize.QuadPart / BUFFER_SIZE;//количество блоков int amount; if (StockFileSize.QuadPart%BUFFER_SIZE != 0)//если не кратно размеру буфера StockNRecord++; if (StockNRecord < n)//если количество блоков меньше количества нитей { n = StockNRecord; //уменьшаем количество нитей amount = 1; //один проход по циклу } else if (StockNRecord == n)//если количество блоков равно количеству нитей amount = 1; //цикл выполняется один раз else amount = StockNRecord / n;//цикл выполняется "Количество_блоков/количество нитей" amount = amount + 1; for (int i = 0; i < n; i++) { hThread[i] = CreateThread(NULL, (10 * 1024 * 1024), newThread, (LPVOID &)i, 0, &dwThreadID); if (hThread[i] == NULL) Error("Поток не создан"); Sleep(0); } amnt = amount; for (q = 0; q < amount; q++) { for (int i = 0; i < n; i++) { EnterCriticalSection(&rdf); ReadFile(hStockFile, forRead[i].buf, BUFFER_SIZE, &forRead[i].count, &StockOver); StockOver.Offset += BUFFER_SIZE; LeaveCriticalSection(&rdf); } while (1)//бесконечный цикл ожидания отрабатывания нитями { if (Flag == flg)//если можно забирать { FlagUse = 1; Flag = 0; break; } else Sleep(10); } WaitForSingleObject(&StockOver.hEvent, INFINITE); sz = StockOver.Offset - StockFileSize.LowPart; for (int i = 0; i < n; i++) { for (int j = 0; j < BUFFER_SIZE; j++) { EnterCriticalSection(&sdf); forSend[i].buf[j] = forRead[i].buf[j]; LeaveCriticalSection(&sdf); } } FlagUse = 0; } END = false; WaitForMultipleObjects(n, hThread, TRUE, INFINITE); for (int i = 0; i < n; i++) CloseHandle(hThread[i]); DeleteCriticalSection(&rdf); DeleteCriticalSection(&sdf); DeleteCriticalSection(&wrt); //CloseHandle(hModFile); CloseHandle(hStockFile); printf("\nОбработка завершена"); _getch(); }
Решение задачи: «Синхронизация потоков с помощью критических секций через общую память»
textual
Листинг программы
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <conio.h> #include <windows.h> #include <locale.h> #include <io.h> #define BUFFER_SIZE 16384 //Размер буфера #define BUFFER_TYPE unsigned char CRITICAL_SECTION rdf, sdf, wrt, CMP; LARGE_INTEGER StockFileSize; volatile long Flag=1; volatile long FlagUse = 1; int amnt; int n = 2;//количество нитей volatile bool END = 1; long long sz = 0; long long szz, of, bsz; int q; OVERLAPPED StockOver; struct sRead //структура для чтения исходного файла { unsigned char buf[BUFFER_SIZE]; DWORD count; }; sRead forRead[256]; struct sSend //структура для передачи в нить { unsigned BUFFER_TYPE buf[BUFFER_SIZE]; DWORD count; DWORD thrd; DWORD amount; DWORD fsize; }; sSend forSend[256]; struct sWrite //структура для записи в новый файл { unsigned BUFFER_TYPE buf[BUFFER_SIZE]; DWORD count; DWORD thrd; DWORD amount; }; sWrite forWrite[256]; void Error(char err[]) { printf("%s", err); _getch(); exit(-1); } DWORD WINAPI newThread(LPVOID lp) { HANDLE hModFile; OVERLAPPED ModOver; DWORD dwCountBytes; LARGE_INTEGER ModFileSize; int name; ModOver.hEvent = CreateEvent(NULL, FALSE, TRUE, NULL); ModOver.Offset = 0; ModOver.OffsetHigh = 0; hModFile = CreateFile("desh.txt", GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_FLAG_OVERLAPPED, NULL); if (hModFile == NULL) Error("Закодированный файл не создан"); volatile int nmb = (int)lp; //получаем номер нити volatile long cmp = 0; //переменная для проверки бита флага, соответствующего номеру нити cmp = 1 << (nmb); int k = 1; while (END) { if ((Flag&cmp) != 1) { while (InterlockedExchange(&FlagUse, 1) == 1)//спин-блокировка Sleep(10); for (int i = 0; i < BUFFER_SIZE; i += 2) { EnterCriticalSection(&sdf); EnterCriticalSection(&wrt); char с = forSend[nmb].buf[i]; forSend[nmb].buf[i] = forSend[nmb].buf[i + 1]; forSend[nmb].buf[i + 1] = с; forWrite[nmb].buf[i] = forSend[nmb].buf[i]; forWrite[nmb].buf[i + 1] = forSend[nmb].buf[i + 1]; LeaveCriticalSection(&wrt); LeaveCriticalSection(&sdf); } of = ModOver.Offset + BUFFER_SIZE; if ((of) > StockFileSize.LowPart) { bsz = BUFFER_SIZE - sz; } else { bsz = BUFFER_SIZE; } EnterCriticalSection(&wrt); WriteFile(hModFile, forWrite[nmb].buf, bsz, &dwCountBytes, &ModOver); GetOverlappedResult(hModFile, &ModOver, &forWrite[nmb].count, TRUE); ModOver.Offset += bsz; LeaveCriticalSection(&wrt); if (k != 1) WaitForSingleObject(ModOver.hEvent, INFINITE); else k++; Flag = Flag | cmp; InterlockedExchange(&FlagUse, 0); //FlagUse = 0; } } CloseHandle(hModFile); return(0); } int main(int argc, char * argv[]) { setlocale(LC_CTYPE, "Russian"); HANDLE hThread[32]; HANDLE hStockFile; HANDLE hModFile; DWORD dwCountBytes; DWORD dwNextSize; DWORD dwThreadID; char StockFileName[30]; char ModFileName[30]; LONGLONG StockNRecord = 1; OVERLAPPED ModOver; InitializeCriticalSection(&rdf); InitializeCriticalSection(&sdf); InitializeCriticalSection(&wrt); volatile long tmp = 0; volatile long flg = 0; //переменная для хранения значения флага, которое появляется в переменной Flag после обработки информации всеми нитями for (int i = 0; i < n; i++) { tmp = 1 << i; flg = flg | tmp; } hStockFile = CreateFile("inf.txt", GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hStockFile == NULL)//если исходный файл не открылся Error("Исходный файл не найден"); StockFileSize.HighPart = 0; StockFileSize.LowPart = GetFileSize(hStockFile, (LPDWORD)StockFileSize.HighPart);//размер файла StockOver.hEvent = CreateEvent(NULL, FALSE, TRUE, NULL); StockOver.Offset = 0; StockOver.OffsetHigh = 0; StockNRecord = StockFileSize.QuadPart / BUFFER_SIZE;//количество блоков int amount; if (StockFileSize.QuadPart%BUFFER_SIZE != 0)//если не кратно размеру буфера StockNRecord++; if (StockNRecord < n)//если количество блоков меньше количества нитей { n = StockNRecord; //уменьшаем количество нитей amount = 1; //один проход по циклу } else if (StockNRecord == n)//если количество блоков равно количеству нитей amount = 1; //цикл выполняется один раз else amount = StockNRecord / n;//цикл выполняется "Количество_блоков/количество нитей" amount = amount + 1; for (int i = 0; i < n; i++) { hThread[i] = CreateThread(NULL, (10 * 1024 * 1024), newThread, (LPVOID &)i, 0, &dwThreadID); if (hThread[i] == NULL) Error("Поток не создан"); Sleep(0); } amnt = amount; for (q = 0; q < amount; q++) { for (int i = 0; i < n; i++) { EnterCriticalSection(&rdf); ReadFile(hStockFile, forRead[i].buf, BUFFER_SIZE, &forRead[i].count, &StockOver); StockOver.Offset += BUFFER_SIZE; LeaveCriticalSection(&rdf); } while (1)//бесконечный цикл ожидания отрабатывания нитями { if (Flag==flg)//если можно забирать { InterlockedExchange(&FlagUse, 1); Flag = 0; break; } else Sleep(10); } WaitForSingleObject(&StockOver.hEvent, INFINITE); sz = StockOver.Offset - StockFileSize.LowPart; for (int i = 0; i < n; i++) { for (int j = 0; j < BUFFER_SIZE; j++) { EnterCriticalSection(&rdf); EnterCriticalSection(&sdf); forSend[i].buf[j] = forRead[i].buf[j]; LeaveCriticalSection(&sdf); LeaveCriticalSection(&rdf); } } InterlockedExchange(&FlagUse, 0); } END = false; WaitForMultipleObjects(n, hThread, TRUE, INFINITE); for (int i = 0; i < n; i++) CloseHandle(hThread[i]); DeleteCriticalSection(&rdf); DeleteCriticalSection(&sdf); DeleteCriticalSection(&wrt); //CloseHandle(hModFile); CloseHandle(hStockFile); printf("\nОбработка завершена"); _getch(); }
ИИ поможет Вам:
- решить любую задачу по программированию
- объяснить код
- расставить комментарии в коде
- и т.д