(我对实现的设计感兴趣,而不是一个可以完成所有工作的现成结构.)

假设我们有一个类HashTable(不是作为树实现的哈希映射,而是哈希表)
并说有八个主题.
假设读写比率约为100:1甚至更好1000:1.
情况A)只有一个线程是编写器,其他包括编写器可以从HashTable读取(它们可能只是遍历整个哈希表)
情况B)所有线程都是相同的,都可以读/写.

有人可以提出最佳策略,以便通过以下考虑使类线程安全
1.最小锁定争用的最高优先级
2.锁定次数最少的第二优先级

到目前为止,我的理解是:
一个BIG读写器锁(信号量).
专门化信号量,以便案例B可以有8个实例编写器资源,其中每个编写器资源锁定一行(或该范围的范围).
(所以我猜1 8个互斥体)

如果我正在考虑正确的路线,请告诉我,我们如何改进这个解决方案.

解决方法

如此高的读/写比率,您应该考虑一个无锁解决方案,例如 nbds.

编辑:

通常,无锁算法的工作方式如下:

>安排您的数据结构,以便对于您打算支持的每个函数,您可以在一个原子操作中确定其结果是否有效(即,其他线程未读取其​​输入,因为它们已被读取并承诺;除非您提交,否则不会更改其他线程可见的状态.这将涉及利用特定于平台的功能,例如Win32的原子比较和交换或Cell的缓存行保留操作码.
>每个受支持的函数都会成为一个循环,重复读取输入并尝试执行工作,直到提交成功为止.

在争用率非常低的情况下,这是对锁定算法的性能优势,因为函数大多数是第一次成功,而不会产生获取锁的开销.随着争用的增加,收益变得更加可疑.

通常,可以原子操作的数据量很小 – 通常是32位或64位 – 因此对于涉及许多读取和写入的函数,生成的算法变得复杂并且可能很难推理.出于这个原因,最好是为您的问题寻找和采用成熟的,经过良好测试和易于理解的第三方无锁解决方案,而不是自己滚动.

Hashtable实现细节将取决于散列和表设计的各个方面.我们希望能够成长吗?如果是这样,我们需要一种方法将旧表中的批量数据安全地复制到新表中.我们是否期望哈希冲突?如果是这样,我们需要一些走路碰撞数据的方法.我们如何确保另一个线程不会删除返回它的查找与使用它的调用者之间的键/值对?也许某种形式的引用计数? – 但谁拥有参考? – 或者只是复制查找值? – 但是如果价值很大怎么办?

无锁堆栈很容易理解,并且实现相对简单(从堆栈中删除一个项目,获取当前顶部,尝试用它的下一个指针替换它,直到你成功,返回它;添加一个项目,获得当前顶部并将其设置为项的下一个指针,直到您成功将指向该项的指针编写为新的顶部;在具有保留/条件写入语义的体系结构上,这就足够了,在仅支持CAS的架构上,您需要附加一个随机数或版本数字到原子操纵的数据,以避免ABA problem).它们是以原子锁自由方式跟踪密钥/数据的可用空间的一种方法,允许您将键/值对(实际存储在哈希表条目中的数据)减少到指针/偏移量或两个,一个小的使用您的架构的原子指令操纵足够的数量.还有其他人.

然后读取成为查找条目的情况,检查kvp与请求的密钥,执行任何操作以确保在我们返回它时保持有效值(获取副本/增加其引用计数),检查条目hasn自从我们开始读取以来已被修改,如果是这样,则返回值,撤消任何引用计数更改并重复读取(如果不是).
写作将取决于我们在碰撞方面所做的工作;在简单的情况下,它们只是找到正确的空槽并编写新的kvp的情况.
以上内容大大简化,不足以产生您自己的安全实现,特别是如果您不熟悉无锁/无等待技术.可能的并发症包括ABA问题,优先级倒置,特定线程的饥饿;我没有解决哈希冲突问题.

nbds页面链接到excellent presentation的真实世界方法,允许增长/碰撞.其他人存在,快速谷歌找到了很多论文.

无锁等待免费算法是研究的迷人领域;我鼓励读者到谷歌周围.也就是说,天真无锁实现可以很容易看起来合理,并且在大多数情况下表现正确,而实际上却是微妙的不安全.虽然掌握这些原则非常重要,但我强烈建议您使用现有的,易于理解且经过验证的实施,而不是自己动手实施.

制作C哈希表的最佳策略,线程安全的更多相关文章

  1. iOS:核心图像和多线程应用程序

    我试图以最有效的方式运行一些核心图像过滤器.试图避免内存警告和崩溃,这是我在渲染大图像时得到的.我正在看Apple的核心图像编程指南.关于多线程,它说:“每个线程必须创建自己的CIFilter对象.否则,你的应用程序可能会出现意外行为.”这是什么意思?我实际上是试图在后台线程上运行我的过滤器,所以我可以在主线程上运行HUD(见下文).这在coreImage的上下文中是否有意义?

  2. ios – 多个NSPersistentStoreCoordinator实例可以连接到同一个底层SQLite持久性存储吗?

    我读过的关于在多个线程上使用CoreData的所有内容都讨论了使用共享单个NSPersistentStoreCoordinator的多个NSManagedobjectContext实例.这是理解的,我已经使它在一个应用程序中工作,该应用程序在主线程上使用CoreData来支持UI,并且具有可能需要一段时间才能运行的后台获取操作.问题是NSPersistentStoreCoordinator会对基础

  3. ios – XCode断点应该只挂起当前线程

    我需要调试多线程错误.因此,为了获得生成崩溃的条件,我需要在代码中的特定点停止一个线程,并等待另一个线程到达第二个断点.我现在遇到的问题是,如果一个线程遇到断点,则所有其他线程都被挂起.有没有办法只停止一个线程,让其他线程运行,直到它们到达第二个断点?)其他更有趣的选择:当你点击第一个断点时,你可以进入控制台并写入这应该在该断点处暂停当前上下文中的线程一小时.然后在Xcode中恢复执行.

  4. ios – 在后台线程中写入Realm后,主线程看不到更新的数据

    >清除数据库.>进行API调用以获取新数据.>将从API检索到的数据写入后台线程中的数据库中.>从主线程上的数据库中读取数据并渲染UI.在步骤4中,数据应该是最新数据,但我们没有看到任何数据.解决方法具有runloops的线程上的Realm实例,例如主线程,updatetothelatestversionofthedataintheRealmfile,因为通知被发布到其线程的runloop.在后台

  5. ios – NSURLConnectionLoader线程中的奇怪崩溃

    我们开始看到我们的应用启动时发生的崩溃.我无法重现它,它只发生在少数用户身上.例外情况是:异常类型:EXC_BAD_ACCESS代码:KERN_INVALID_ADDRESS位于0x3250974659崩溃发生在名为com.apple.NSURLConnectionLoader的线程中在调用时–[NSBlockOperationmain]这是该线程的堆栈跟踪:非常感谢任何帮助,以了解可能导致这种崩

  6. ios – 合并子上下文时的NSObjectInaccessbileExceptions

    我尝试手动重现,但失败了.是否有其他可能发生这种情况的情况,是否有处理此类问题的提示?解决方法在创建子上下文时,您可以尝试使用以下行:

  7. ios – 从后台线程调用UIKit时发出警告

    你如何处理项目中的这个问题?

  8. ios – 在SpriteKit中,touchesBegan在与SKScene更新方法相同的线程中运行吗?

    在这里的Apple文档AdvancedSceneProcessing中,它描述了更新方法以及场景的呈现方式,但没有提到何时处理输入.目前尚不清楚它是否与渲染循环位于同一个线程中,或者它是否与它并发.如果我有一个对象,我从SKScene更新方法和touchesBegan方法(在这种情况下是SKSpriteNode)更新,我是否要担心同步对我的对象的两次访问?解决方法所以几天后没有回答我设置了一些实验

  9. ios – 在后台获取中加载UIWebView

    )那么,有一种方法可以在后台加载UIWebView吗?解决方法如果要从用户界面更新元素,则必须在应用程序的主队列(或线程)中访问它们.我建议您在后台继续获取所需的数据,但是当需要更新UIWebView时,请在主线程中进行.你可以这样做:或者您可以创建一个方法来更新UIWebView上的数据,并使用以下方法从后台线程调用它:这将确保您从正确的线程访问UIWebView.希望这可以帮助.

  10. ios – 何时使用Semaphore而不是Dispatch Group?

    我会假设我知道如何使用DispatchGroup,为了解问题,我尝试过:结果–预期–是:为了使用信号量,我实现了:并在viewDidLoad方法中调用它.结果是:从概念上讲,dispachGroup和Semaphore都有同样的目的.老实说,我不熟悉:什么时候使用信号量,尤其是在与dispachGroup合作时–可能–处理问题.我错过了什么部分?

随机推荐

  1. 从C到C#的zlib(如何将byte []转换为流并将流转换为byte [])

    我的任务是使用zlib解压缩数据包(已接收),然后使用算法从数据中生成图片好消息是我在C中有代码,但任务是在C#中完成C我正在尝试使用zlib.NET,但所有演示都有该代码进行解压缩(C#)我的问题:我不想在解压缩后保存文件,因为我必须使用C代码中显示的算法.如何将byte[]数组转换为类似于C#zlib代码中的流来解压缩数据然后如何将流转换回字节数组?

  2. 为什么C标准使用不确定的变量未定义?

    垃圾价值存储在哪里,为什么目的?解决方法由于效率原因,C选择不将变量初始化为某些自动值.为了初始化这些数据,必须添加指令.以下是一个例子:产生:虽然这段代码:产生:你可以看到,一个完整的额外的指令用来移动1到x.这对于嵌入式系统来说至关重要.

  3. 如何使用命名管道从c调用WCF方法?

    更新:通过协议here,我无法弄清楚未知的信封记录.我在网上找不到任何例子.原版的:我有以下WCF服务我输出添加5行,所以我知道服务器是否处理了请求与否.我有一个.NET客户端,我曾经测试这一切,一切正常工作预期.现在我想为这个做一个非托管的C客户端.我想出了如何得到管道的名称,并写信给它.我从here下载了协议我可以写信给管道,但我看不懂.每当我尝试读取它,我得到一个ERROR_broKEN_P

  4. “这”是否保证指向C中的对象的开始?

    我想使用fwrite将一个对象写入顺序文件.班级就像当我将一个对象写入文件时.我正在游荡,我可以使用fwrite(this,sizeof(int),2,fo)写入前两个整数.问题是:这是否保证指向对象数据的开始,即使对象的最开始可能存在虚拟表.所以上面的操作是安全的.解决方法这提供了对象的地址,这不一定是第一个成员的地址.唯一的例外是所谓的标准布局类型.从C11标准:(9.2/20)Apointe

  5. c – 编译单元之间共享的全局const对象

    当我声明并初始化一个const对象时.两个cpp文件包含此标头.和当我构建解决方案时,没有链接错误,你会得到什么如果g_Const是一个非const基本类型!PrintInUnit1()和PrintInUnit2()表明在两个编译单元中有两个独立的“g_Const”具有不同的地址,为什么?

  6. 什么是C名称查找在这里? (&GCC对吗?)

    为什么在第三个变体找到func,但是在实例化的时候,原始变体中不合格查找找不到func?解决方法一般规则是,任何不在模板定义上下文中的内容只能通过ADL来获取.换句话说,正常的不合格查找仅在模板定义上下文中执行.因为在定义中间语句时没有声明func,并且func不在与ns::type相关联的命名空间中,所以代码形式不正确.

  7. c – 在输出参数中使用auto

    有没有办法在这种情况下使用auto关键字:当然,不可能知道什么类型的.因此,解决方案应该是以某种方式将它们合并为一个句子.这可用吗?解决方法看起来您希望默认初始化给定函数期望作为参数的类型的对象.您无法使用auto执行此操作,但您可以编写一个特征来提取函数所需的类型,然后使用它来声明您的变量:然后你就像这样使用它:当然,只要你重载函数,这一切都会失败.

  8. 在C中说“推动一切浮动”的确定性方式

    鉴于我更喜欢将程序中的数字保留为int或任何内容,那么使用这些数字的浮点数等效的任意算术最方便的方法是什么?说,我有我想写通过将转换放在解析的运算符树叶中,无需将表达式转化为混乱是否可以使用C风格的宏?应该用新的类和重载操作符完成吗?解决方法这是一个非常复杂的表达.更好地给它一个名字:现在当您使用整数参数调用它时,由于参数的类型为double,因此使用常规的算术转换将参数转换为double用C11lambda……

  9. objective-c – 如何获取未知大小的NSArray的第一个X元素?

    在objectiveC中,我有一个NSArray,我们称之为NSArray*largeArray,我想要获得一个新的NSArray*smallArray,只有第一个x对象…

  10. c – Setprecision是混乱

    我只是想问一下setprecision,因为我有点困惑.这里是代码:其中x=以下:方程的左边是x的值.1.105=1.10应为1.111.115=1.11应为1.121.125=1.12应为1.131.135=1.14是正确的1.145=1.15也正确但如果x是:2.115=2.12是正确的2.125=2.12应为2.13所以为什么在一定的价值是正确的,但有时是错误的?请启发我谢谢解决方法没有理由期望使用浮点系统可以正确地表示您的帖子中的任何常量.因此,一旦将它们存储在一个双变量中,那么你所拥有的确切的一

返回
顶部