读取时的IPC同步问题&写入共享文件

时间:2015-04-22 05:53:00

标签: c++ windows winapi synchronization ipc

在访问一组共享文件时,从几个同时运行的进程中调用以下代码。这些文件包含条目的列表。 (我提到文件(pl。)的原因仅仅是因为带有条目的实际列表被分解为磁盘上的较小文件。)

规定是每个条目必须具有唯一的自动递增ID。为此,我正在实现一个用于文件访问同步的命名互斥锁,但显然我仍然遗漏了一些东西,因为有时我会在那些条目中重复或重复ID(下面的dwUniqueID变量)

有人能说明原因吗?

接下来是简要代码,为简洁起见省略了所有错误检查。我还将其剥离为裸API调用:

//Global variables
HANDLE hFile = INVALID_HANDLE_VALUE;
HANDLE hMutex = NULL;

然后初始化(完成一次):

//INFO: Error checks are omitted for brevity!

PSECURITY_DESCRIPTOR psdMutex = NULL;
::ConvertStringSecurityDescriptorToSecurityDescriptor(
    L"D:(A;;GA;;;WD)(A;;GA;;;AN)S:(ML;;;;;S-1-16-0)",
    SDDL_REVISION_1, &psdMutex, NULL);

SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof(sa);
sa.bInheritHandle = FALSE;
sa.lpSecurityDescriptor = psdMutex;

//Create global IPC mutex
hMutex = ::CreateMutex(&sa, FALSE, L"Global\\My_IPC_Mutex_Name");

::LocalFree(psdMutex);

然后第一次打开所需文件之一:

//INFO: Error checks are omitted for brevity!

//Open initial file
ReopenFile();

void ReopenFile()
{
    //Close previous file
    if(hFile != INVALID_HANDLE_VALUE)
    {
        ::FlushFileBuffers(hFile);
        ::CloseHandle(hFile);
        hFile = INVALID_HANDLE_VALUE;   
    }

    //Create/open file
    hFile = ::CreateFile(strFilePath, 
        GENERIC_READ | GENERIC_WRITE,
        FILE_SHARE_READ | FILE_SHARE_WRITE,
        NULL,
        OPEN_ALWAYS,
        FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH,
        NULL);
}

然后,为了测试我的IPC同步,我在一个长循环中调用以下代码:

//INFO: Error checks are omitted for brevity!
for(;;){

//Enter IPC critical section
if(::WaitForSingleObject(hMutex, INFINITE) ==  WAIT_OBJECT_0)
{
    //Read last DWORD from file
    DWORD dwUniqueID = 0, ncbWrtn;

    LARGE_INTEGER liFileSz = {0};
    ::GetFileSizeEx(hFile, &liFileSz);
    if(liFileSz.QuadPart >= sizeof(DWORD))
    {
        LARGE_INTEGER li0;
        li0.QuadPart = -(LONGLONG)(sizeof(DWORD));
        ::SetFilePointerEx(hFile, li0, NULL, FILE_END);

        ::ReadFile(hFile, &dwUniqueID, sizeof(DWORD), &ncbWrtn, NULL);
    }

    //Do other work
    //...

    if(CheckIfThisFileIsFull(liFileSz))
    {
        //File must be closed and another one opened
        ReopenFile();
    }

    //Increment unique ID
    dwUniqueID++;

    //And write it into file
    LARGE_INTEGER li1 = {0};
    ::SetFilePointerEx(hFile, li1, NULL, FILE_END);
    ::WriteFile(hFile, &dwUniqueID, sizeof(DWORD), &ncbWrtn, NULL);

    //Flush file
    ::FlushFileBuffers(hFile);

    //Leave IPC critical section
    ::ReleaseMutex(hMutex);
}
else break;

}

2 个答案:

答案 0 :(得分:0)

FlushFileBuffers的MSDN文档让我相信Windows仍然可以缓存写入操作,因此在发布互斥锁时,不保证文件与其他进程保持一致。

答案 1 :(得分:0)

我想我得到了自己问题的答案。我获得重复ID的原因是因为我的实现逻辑错误:当我的CheckIfThisFileIsFull()方法确定当前文件已满时,它会出现一个新文件然后ReopenFile()将打开并且开始使用它。好吧,如果有多个进程使用此方法,则无效。例如,如果一个进程仍然保留旧文件,而另一个进程已经创建了一个新文件,则第一个进程将不知道它,从而重用旧ID并创建副本。

无论如何,我感谢您的意见...如果您从原始帖子中的ReopenFile()循环中删除for(;;),我的实现将适用于多进程应用程序(即不需要额外的锁定。)