C中链表的同时修改

时间:2017-03-21 20:41:42

标签: c multithreading concurrency concurrentmodification locks

我已经编写了一个C应用程序来对DNS服务器(在VM上运行)进行压力测试,我试图获得最大的DNS请求率(吞吐量),以了解它的行为方式。
我的应用程序运行两个线程,发送生成DNS请求(具有不同查询名称)的线程,并将它们发送到服务器上的套接字和接收线程,该接收线程在同一套接字上接收DNS响应并计算响应时间。

现在使用并发链表(我已经实现),发送线程为每个发送的请求附加查询名称和发送时间(到列表的末尾)。接收线程每次从开始运行,查找具有相关发送时间的查询名称,计算响应时间并从列表中删除对象,它遍历的每个对象都检查发送时间是否在DNS超时窗口内设置,如果不是,我将此请求视为未答复,并将其从列表中删除。

现在的问题是我每次都必须锁定接收线程中包含节点删除的列表的整个遍历,它会严重影响停止发送的发送线程,等待很多时间在锁上追加

您建议在我的情况下实施锁定有不同的方式吗?或者是否有更重要的东西可以改变?

PS:我曾尝试在脚本中使用unix挖掘并在python scapy中实现相同但无法达到我在C app中达到的速率(没有锁定的发送高达10 Mbit),这就是为什么我选择在C中实现它。

谢谢!

1 个答案:

答案 0 :(得分:1)

接收线程扫描时,您可能需要锁定整个列表。发送线程只会修改当前的最后一个节点(以附加一个新节点),只要它保持指向当前尾部的指针,它就不需要检查任何其他节点。就其本身而言,接收线程可以移除除当前尾部之外的任何节点而不会对发送线程产生任何影响。因此,只需要锁定尾节点。

在当前尾部维护移动锁可能有点棘手,因为你需要知道哪个节点,但我认为它不会太难。例如,您可以提供一个指向尾部的共享原子指针,发送方在发送每个请求之前更新,接收方在接收到响应时读取。接收方不需要考虑任何后续请求(因为当收到当前响应时尚未发送它们)。

接收方有时可能需要等待发送方附加至少一个请求,以便可以删除之前的尾部,但我希望这种情况很少见。否则,我看不到您的列表现在如何变得如此之长,以至于在扫描时将整个事物锁定太耗时。