Синхронизация потоков с помощью критических секций через общую память - 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();
}

ИИ поможет Вам:


  • решить любую задачу по программированию
  • объяснить код
  • расставить комментарии в коде
  • и т.д
Попробуйте бесплатно

Оцени полезность:

13   голосов , оценка 4.231 из 5
Похожие ответы