使用文件作为 CreateFile() 的互斥锁

Using file as a mutex with CreateFile()

我接到了创建 2 个进程的任务。第一个打开文件“log.txt”并将用户提供的输入添加到其中。 第二个进程是该文件的“监视器”。它检查它是否存在,给出它的大小并给出自第二个过程开始以来用户输入的字符数。我正在对它使用 GetFileSize() 函数,所以这不是问题。

我对 CreateProcess() 和 CreateFile() 函数有点困惑,因为我不确定如何将它们相互连接。

我了解到 CreateFile() 函数可以通过更改其标志来用作互斥锁。我想到了这样的事情:

HANDLE hFile = CreateFile(
                    "log.txt",
                    FILE_APPEND_DATA,
                    FILE_SHARE_WRITE | FILE_SHARE_READ,
                    0,
                    OPEN_ALWAYS,
                    FILE_ATTRIBUTE_NORMAL,
                    0);

现在我不太确定如何将它连接到进程以及从哪里启动进程。而且我也不知道如何检查自第二个过程开始以来给出了多少个字符。

有人可以向我解释何时启动这 2 个进程以及如何将 CreateFile() 函数连接到它们吗?

您似乎想要同步这两个进程,以便第二个进程等待第一个进程完成写入“log.txt”。

为此,您需要在第一个进程中以独占访问权限打开该文件(无 FILE_SHARE_WRITE | FILE_SHARE_READ),并在完成写入后将其关闭。

第二个进程将尝试打开同一个文件,同样具有独占访问权限。如果第一个进程仍在使用该文件,CreateFile() 将失败并显示“访问被拒绝”错误。这是mutex的“互斥”概念的本质。然后您稍等片刻再试。

与同步对象相反,我不知道等待文件可用的方法(使用 WaitForSingleObject 互斥很容易完成)。

FILE_SHARE_WRITE | FILE_SHARE_READ将允许其他进程打开并共享读写权限。您需要以独占方式打开文件(使用 dwShareMode = 0),但这需要 process2 尝试在循环中以独占方式打开文件。 相反,使用 CreateMutex to create a mutex, then process1 uses WaitForSingleObject to take up the mutex, do something and then ReleaseMutex,process2 使用 WaitForSingleObject 等待释放互斥锁,然后读取文件。 (一次同步完成)

进程 2:

#include <windows.h>
#include <iostream>
 
int wmain(int argc, wchar_t* argv[])
{
    HANDLE hMutex = OpenMutex(MUTEX_ALL_ACCESS, false, L"MyMutex");

    DWORD dwWaitResult = WaitForSingleObject(hMutex, INFINITE);
    if (dwWaitResult == WAIT_OBJECT_0)
    {
        HANDLE hFile = CreateFile(L"log.txt", FILE_READ_ATTRIBUTES, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
        if (hFile == INVALID_HANDLE_VALUE)
        {
            std::cout << "CreateFile error " << GetLastError() << std::endl;
            ReleaseMutex(hMutex);
        }
        else
        {
            DWORD size = GetFileSize(hFile, NULL);
            std::cout << "File Size: " << size << std::endl;
            CloseHandle(hFile);
            ReleaseMutex(hMutex);
        }
    }
    return 0;
}

进程 1:

#include <windows.h>
#include <iostream>
int wmain(int argc, wchar_t* argv[])
{
    HANDLE hMutex = CreateMutex(NULL, false, L"MyMutex");
    DWORD dwWaitResult = WaitForSingleObject(hMutex, INFINITE);
    if (dwWaitResult == WAIT_OBJECT_0)
    {
        STARTUPINFO si = { 0 };
        si.cb = sizeof(si);
        PROCESS_INFORMATION pi = { 0 };
        CreateProcess(L"process2.exe",
            NULL,
            NULL,
            NULL,
            false,
            CREATE_NEW_CONSOLE,
            NULL,
            NULL,
            &si,
            &pi);
        std::string buffer;
        std::cin >> buffer;
        HANDLE hFile = CreateFile(L"log.txt", FILE_APPEND_DATA, 0, 0, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
        DWORD written = 0;
        WriteFile(hFile, buffer.c_str(), buffer.size(), &written, NULL);
        CloseHandle(hFile);
        ReleaseMutex(hMutex);
    }
    return 0;
}

但是这样比较麻烦,因为每次都需要同步两个进程。 正如@Remy Lebeau 所说,在 process2:

中使用 ReadDirectoryChangesW
#include <windows.h>
#include <iostream>
 
int wmain(int argc, wchar_t* argv[])
{
    FILE_NOTIFY_INFORMATION* pInfo = NULL;

    HANDLE hFile = CreateFile(L"Directory of log.txt", GENERIC_READ, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS, 0);

    while (1)
    {
        DWORD returned = 0;
        DWORD dwOffset = 0;
        BYTE szBuffer[1024] = { 0 };
        
        ReadDirectoryChangesW(hFile, szBuffer, sizeof(szBuffer), false, FILE_NOTIFY_CHANGE_SIZE, &returned, NULL, NULL);
        do
        {
            pInfo = (FILE_NOTIFY_INFORMATION*)&szBuffer[dwOffset];
            if (wcscmp(pInfo->FileName, L"log.txt") == 0)
            {
                HANDLE hFile = CreateFile(L"path\log.txt", FILE_APPEND_DATA, 0, 0, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
                DWORD size = GetFileSize(hFile, NULL);
                std::cout << "File Size: " << size << std::endl;
                CloseHandle(hFile);
            }
            dwOffset += pInfo->NextEntryOffset;
        } while (pInfo->NextEntryOffset != 0);
    }
    return 0;
}

而进程1只需要获取用户输入并写入文件:

#include <windows.h>
#include <iostream>
int wmain(int argc, wchar_t* argv[])
{
    std::string buffer;
    while (1)
    {
        std::cin >> buffer;
        HANDLE hFile = CreateFile(L"log.txt", FILE_APPEND_DATA, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
        DWORD written = 0;
        WriteFile(hFile, buffer.c_str(), buffer.size(), &written, NULL);
        CloseHandle(hFile);
    }
    return 0;
}

所以我设法从您宝贵的意见中做出了一些贡献。我不确定这是否是解决此任务的正确方法。如果有人可以查看我的代码并给我一些额外的提示,那就太好了。

这是我的代码

int main(int argc, char *argv[])
{

    STARTUPINFO si;
    PROCESS_INFORMATION pi;

    ZeroMemory(&si, sizeof(si));
    ZeroMemory(&pi, sizeof(pi));

    si.cb = sizeof(si);
    CreateProcess("process2.exe",
        NULL,
        NULL,
        NULL,
        false,
        CREATE_NEW_CONSOLE,
        NULL,
        NULL,
        &si,
        &pi);

        std::string buffer;
        std::cout << "Enter your text:" << std::endl;
        getline(std::cin, buffer);
        HANDLE hFile = CreateFile("log.txt", FILE_APPEND_DATA, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
        DWORD written = 0;
        WriteFile(hFile, buffer.c_str(), buffer.size(), &written, NULL);



        hFile = CreateFile("log.txt", FILE_READ_ATTRIBUTES, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
        if (hFile == INVALID_HANDLE_VALUE)
        {
            std::cout << "CreateFile error " << GetLastError() << std::endl;
        }
        else
        {
            DWORD size = GetFileSize(hFile, NULL);
            std::cout << "\nCurrent file size: " << size << std::endl;
            CloseHandle(hFile);
        }

        int stringLenght = 0;
        for(int i=0; buffer[i]; i++)
            stringLenght++;

            std::cout << "\nCharacters given since last startup: " << stringLenght << std::endl;

 return 0;
 }

我不确定这是否是此任务的重点,或者它是否应该检查文件大小并在 while 循环中要求用户输入,以及是否可以在没有互斥锁的情况下完成。