我有一个简单的std :: map,它有键值。我希望这张地图是线程安全的。我不想锁定整个地图。由于我的线程仅对地图中特定键的值起作用(更新,删除),我不希望锁定整个地图。我希望其他线程能够在地图上工作,当然不是锁定值。
仅锁定特定密钥的值是明智还是逻辑正确?或者我应该想到另一种数据结构?
更新:我刚刚尝试了一个示例示例,其中我有并行线程更新并插入到同一个地图中。
#include "stdafx.h"
#include "stdafx.h"
#include <iostream>
#include <map>
#include <process.h>
#include <windows.h>
using namespace std;
CRITICAL_SECTION CriticalSection;
struct newEntry
{
int key;
char value;
};
std::map<int,char> mapIntChar;
unsigned __stdcall UpdateThreadFunc( void* pArguments )
{
char *ptr = (char *) pArguments;
EnterCriticalSection(&CriticalSection);
*ptr = 'Z';
LeaveCriticalSection(&CriticalSection);
_endthreadex( 0 );
return 0;
}
unsigned __stdcall InsertThreadFunc( void* pArguments )
{
struct newEntry *ptr = (struct newEntry *) pArguments;
mapIntChar[ptr->key] = ptr->value;
_endthreadex( 0 );
return 0;
}
int _tmain(int argc, _TCHAR* argv[])
{
std::map<int,char>::iterator it1;
unsigned threadID;
if (!InitializeCriticalSectionAndSpinCount(&CriticalSection,
0x00000400) )
return 0;
mapIntChar[0] = 'A';
mapIntChar[1] = 'B';
mapIntChar[2] = 'C';
mapIntChar[3] = 'D';
HANDLE hThread;
int nCount = 0;
struct newEntry *newIns;
while ( nCount < 1004)
{
it1 = mapIntChar.begin();
char *ptr = &(it1->second);
hThread = (HANDLE)_beginthreadex( NULL, 0, &UpdateThreadFunc, ptr, 0, &threadID );
newIns = new newEntry;
newIns->key = rand() % 1000;
newIns->value = 'K';
hThread = (HANDLE)_beginthreadex( NULL, 0, &InsertThreadFunc, newIns, 0, &threadID );
nCount++;
delete newIns;
}
}
答案 0 :(得分:2)
您可以围绕std::map
创建一个包装器(或者更确切地说,将容器类型作为模板参数,以便您可以使用类似的容器,如std::unordered_map
或std::set
),这些容器具有以下功能:锁定特定条目。
包装类必须镜像实际std::map
类中的方法,其实现包含对锁的检查,否则只需调用基础容器类型中的方法。
答案 1 :(得分:0)
如果地图已经为您要修改的每个键都有一个条目,那么您应该能够在不同的线程上修改这些键的值,只要每个线程使用一组不重叠的键,和只要没有修改地图本身的结构(即不修改地图中的一组键,或以其他方式调整其大小)。
那就是说,从技术上讲,这只适用于C ++ 11。在此之前,C ++假装线程不存在,并且在多个线程运行时根本不保证内存模型。