使用文件作为 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 循环中要求用户输入,以及是否可以在没有互斥锁的情况下完成。
我接到了创建 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 循环中要求用户输入,以及是否可以在没有互斥锁的情况下完成。