C 使用互斥锁锁定对列表对象的所有访问

C 使用互斥锁锁定对列表对象的所有访问,c,multithreading,object,winapi,mutex,C,Multithreading,Object,Winapi,Mutex,我想创建一些代码,允许创建支持多线程操作的列表。我的想法很简单:每当线程想要对列表进行操作时,它都应该调用LockList,当它完成时,它应该调用UnlockList。这样,其他线程对锁定对象的任何其他api调用都将导致失败,并且只有所有者线程才能使用该对象 我对它进行了测试,令人惊讶的是,我没有崩溃,但相反,在所有线程完成对列表的操作后,at cleanup LockList恰好失败一次,然后一切都按预期工作 以下是锁定列表和解锁列表功能的定义: WINBOOL APIENTRY LockLi

我想创建一些代码,允许创建支持多线程操作的列表。我的想法很简单:每当线程想要对列表进行操作时,它都应该调用LockList,当它完成时,它应该调用UnlockList。这样,其他线程对锁定对象的任何其他api调用都将导致失败,并且只有所有者线程才能使用该对象

我对它进行了测试,令人惊讶的是,我没有崩溃,但相反,在所有线程完成对列表的操作后,at cleanup LockList恰好失败一次,然后一切都按预期工作

以下是锁定列表和解锁列表功能的定义:

WINBOOL APIENTRY LockList (HANDLE hList)
{
    #define lpList ((LPLIST_INFO)hList)
    DWORD dwState = WaitForSingleObject(lpList->hMutex, 0);
    if(dwState != WAIT_OBJECT_0)
        return FALSE;

    return TRUE;
    #undef lpList
}

WINBOOL APIENTRY UnlockList (HANDLE hList)
{
    #define lpList ((LPLIST_INFO)hList)
    DWORD dwState = WaitForSingleObject(lpList->hMutex, 0);
    if(dwState != WAIT_OBJECT_0)
        return FALSE;

    ReleaseMutex(lpList->hMutex);
    return TRUE;
    #undef lpList
}
我试着通过让一些线程在列表中插入项目来测试我的代码,更具体地说,我制作了一个学生列表。这是代码的重要部分:

DWORD APIENTRY ThreadProc(LPVOID lpvList)
{
    #define hList ((HANDLE)lpvList)

    for(DWORD I = 0; I < 1000; I++)
    {
        // wait until the thread gets ownership of the mutex ...
        while(!LockList(hList)); 

        // Insert the entity into the list ...

        UnlockList(hList);
    }

    RETURN 0;
    #undef hList
}

#define WORKER_COUNT 40
INT WINAPI WinMain(HINSTANCE hThisInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, INT nCmdShow)
{
    // An anonymous mutex is created with bInitialOwner FALSE
    HANDLE hList = CreateList(GetProcessHeap(), 0, StudentConstructor, StudentDestructor);
    if(hList == NULL)
        return MessageBoxA(HWND_DESKTOP, "Could not create list.", "Runtime Error", MB_OK|MB_ICONERROR);

    HANDLE hThreads[WORKER_COUNT];
    DWORD dwThreadIds[WORKER_COUNT];

    for(DWORD I = 0; I < WORKER_COUNT; I++)
    {
        hThreads[I] = CreateThread(NULL, 0, ThreadProc, hList, 0, &dwThreadIds[I]);
        if(hThreads[I] == NULL)
            return MessageBoxA(HWND_DESKTOP, "Could not create worker thread.", "Runtime Error", MB_OK|MB_ICONERROR);
    }

    WaitForMultipleObjects(WORKER_COUNT, hThreads, TRUE, INFINITE);

    for(DWORD I = 0; I < WORKER_COUNT; I++)
        CloseHandle(hThreads[I]);

    while(!LockList(hList))
        printf("Could not get ownership of the list.\n");

    printf("The list has %lu entities.\n", GetListEntityCount(hList));

    if(!DeleteList(hList))
        return MessageBoxA(HWND_DESKTOP, "Could not delete list.", "Runtime Error", MB_OK|MB_ICONERROR);

    return 0;
}

我是否正确使用WaitForSingleObject?为什么即使所有线程都释放了互斥锁的所有权,锁列表也会失败一次?

您的锁/解锁语义不平衡

互斥句柄上对WaitForSingleObject的每次调用都需要与释放互斥windows互斥对象的调用配对,互斥对象允许同一线程进行多次采集

现在如果你有锁列表;解锁列表

这意味着: 等待线程结束 等待线程结束
释放互斥锁

您具有不平衡的锁定/解锁语义

互斥句柄上对WaitForSingleObject的每次调用都需要与释放互斥windows互斥对象的调用配对,互斥对象允许同一线程进行多次采集

现在如果你有锁列表;解锁列表

这意味着: 等待线程结束 等待线程结束
释放互斥体

那么我如何检查互斥体是否拥有/未拥有,而不实际获得所有权?这实际上是一个很难回答的问题…whileReleaseMutexlpList->hMutex==TRUE;在UnlockList函数中?这是一个好的做法吗?@Tudor“我如何检查互斥锁是否拥有/未拥有,而不实际获得所有权?”-你不能。无论如何,不能使用Win32互斥锁。这方面没有API。您必须更改您的设计,使其不调用UnlockList中的WaitForSingleObject。除非LockList报告为true,否则不要调用UnlockList。不要在忙循环中调用锁列表。如果您想等待获得互斥对象的所有权,只需调用WaitForSingleObject 1次并无限超时。@Tudor“在UnlockList函数中调用whileReleaseMutexlpList->hMutex==TRUE如何?这是一种好的做法吗?”-绝对不是。这是一种可怕的做法,并且会带来更多的问题。通常的答案是只有当你知道自己拥有所有权时才解锁。您的锁列表实际上会等待线程能够锁定互斥锁。即以下顺序:WaitForSingleObjecthMutex,无限;/*锁定操作*/releasemutexmutex;那么,我如何检查互斥锁是否拥有/未拥有,而不实际获得它的所有权呢?这实际上是一个很难回答的问题…whileReleaseMutexlpList->hMutex==TRUE;在UnlockList函数中?这是一个好的做法吗?@Tudor“我如何检查互斥锁是否拥有/未拥有,而不实际获得所有权?”-你不能。无论如何,不能使用Win32互斥锁。这方面没有API。您必须更改您的设计,使其不调用UnlockList中的WaitForSingleObject。除非LockList报告为true,否则不要调用UnlockList。不要在忙循环中调用锁列表。如果您想等待获得互斥对象的所有权,只需调用WaitForSingleObject 1次并无限超时。@Tudor“在UnlockList函数中调用whileReleaseMutexlpList->hMutex==TRUE如何?这是一种好的做法吗?”-绝对不是。这是一种可怕的做法,并且会带来更多的问题。通常的答案是只有当你知道自己拥有所有权时才解锁。您的锁列表实际上会等待线程能够锁定互斥锁。即以下顺序:WaitForSingleObjecthMutex,无限;/*锁定操作*/releasemutexmutex;
// ...
DWORD dwState = WaitForSingleObject(lpList->hMutex, 0);
if(dwState != WAIT_OBJECT_0)
    return FALSE; // or NULL or whatever signals failure.
// ...