【问题标题】:Hash table entry linked list - Mutex locks for thread safe operation哈希表条目链表 - 用于线程安全操作的互斥锁
【发布时间】:2012-02-19 00:36:57
【问题描述】:

Win32 Mutex 是限制线程访问哈希表中链表的最有效方法吗?我不想创建很多句柄,并且哈希表的大小是可变的。它可能是数千个。当只有一个条目的列表被更改时,我不想锁定整个列表,所以这将需要多个互斥锁(每个列表一个),但我想我可能会通过汇集大约 20 个互斥锁句柄并重用来侥幸他们,因为不应该有那么多线程同时访问它。对于这种情况,是否有互斥锁的替代品?

【问题讨论】:

  • 如果线程都在同一个进程中,我会使用临界区而不是互斥体
  • 那么在 Win32 中调用 InitializeCriticalSection()、EnterCriticalSection()、LeaveCriticalSection() API 吗?
  • 是的,操作比互斥锁简单得多,但只能在单个进程中工作
  • 关键部分+1。另外,评论原曲;我对池化方法很好奇:似乎这需要跟踪池中的每个锁与哪个列表(如果有)相关联,需要另一个数据结构,然后它本身就需要一个锁...... :)跨度>
  • 但是拥有一个包含 1033 个或更多条目且每个条目都带有锁的哈希表总共需要 24792 个字节(每个 CRITICAL_SECTION 结构 24 个字节)。这就是为什么我可以创建一个包含大约 20 个节点(20 x 24 = 480 字节)的池(带有单个锁)。我猜这是内存与速度的权衡。不应该有那么多线程在运行,所以我认为即使池有锁,它也不会受到太大影响。

标签: winapi list hash mutex


【解决方案1】:

这里很大程度上取决于您的哈希表的详细信息。我的直接反应是完全避免使用互斥体/关键部分,至少如果可以的话。

至少对于将项目添加到链接列表,使用InterlockedExchangePointer 代替它很容易避免它。大概你有一个类似的结构:

struct LL_item { 
    LL_item *next;
    std::string key;
    whatever_type value;
};

要将这种类型的项目插入到链表中,您可以执行以下操作:

LL_item *item = new LL_item;

// set key and value here
item->next = &item;
InterlockedExchangePointer(&item->next, &bucket->head);

InterlockedExchangePointer 之前,bucket->head 包含当前列表中第一项的地址。我们在 next 指针中使用它自己的地址初始化我们的新项目。然后我们(原子地)将新项目中的下一个指针与指向列表中(前一个)第一个节点的指针交换。交换后,新节点的next指针包含了链表中前一项的地址,指向链表头的指针包含了我们新节点的地址。

我相信您通常也可以(可能)使用交换来从列表中删除项目,但我不确定——我还没有彻底考虑过这一点。无论如何,相当多的哈希表不(甚至尝试)不支持删除,因此您可能并不关心这一点。

【讨论】:

  • 您不想使用InterlockedCompareExchangePointer 吗? msdn.microsoft.com/en-us/library/windows/desktop/ms683568.aspx
  • @JimMischel:你的意思是从列表中删除一个项目吗?在那种情况下,是的,可能。如果您正在谈论插入列表,我不确定您从比较中获得了什么。
  • 也许我误解了什么。我对InterlockedExchangePointer 文档的阅读表明&item->next 的值会改变,但&bucket->head 的值不会改变。我建议使用InterlockedCompareExchangePointer 并不能解决这个问题。类似问题的公认答案表明两个内存位置没有原子交换:stackoverflow.com/questions/4503628/…
【解决方案2】:

我建议slim reader writer lock。当然,当您进行更新时,它会锁定整个数据结构,但通常您对哈希表的读取次数要比写入次数多得多。我对 SRW 锁的经验是它工作得很好,性能也很好。你可能应该试一试。这将使您的程序正常工作。然后您可以分析代码以确定是否存在瓶颈以及瓶颈在哪里。 SRW 锁很可能足够快。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多