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