Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ C+中的多线程链表+;_C++_Multithreading_Linked List_Singly Linked List - Fatal编程技术网

C++ C+中的多线程链表+;

C++ C+中的多线程链表+;,c++,multithreading,linked-list,singly-linked-list,C++,Multithreading,Linked List,Singly Linked List,首先,对我要做的事情做一点解释: 我的计划是使用boost::asio库实现的套接字流编写一个程序,该库将数据提供给使用boost:spirit::qi实现的解析器。解析器将获取数据包并填充数据包对象,然后将该对象附加到数据包对象链接列表的末尾。数据包处理器将读取列表中的第一个对象并进行处理,然后移动到下一个项目并删除第一个项目 我决定使用链表,因为如果我使用std::queue,每次流添加数据包或处理器删除数据包时,我都必须锁定整个容器,这将使两个线程或多或少连续运行,我希望避免这种情况。此外

首先,对我要做的事情做一点解释:

我的计划是使用boost::asio库实现的套接字流编写一个程序,该库将数据提供给使用boost:spirit::qi实现的解析器。解析器将获取数据包并填充数据包对象,然后将该对象附加到数据包对象链接列表的末尾。数据包处理器将读取列表中的第一个对象并进行处理,然后移动到下一个项目并删除第一个项目

我决定使用链表,因为如果我使用std::queue,每次流添加数据包或处理器删除数据包时,我都必须锁定整个容器,这将使两个线程或多或少连续运行,我希望避免这种情况。此外,queue类倾向于复制整个对象,而链表思想的好处是只创建一次对象,然后指向它。为了避免序列化整个业务,我打算在每个节点中放置boost:mutex互斥体,并从那里锁定它们。其思想是让套接字流创建列表并立即锁定第一个节点,从解析器填充节点,创建下一个节点并锁定它,然后解锁第一个节点并移动到下一个节点进行工作。这样,就不会有一个未锁定的节点悬空在最后,包进程可以跳转到套接字流鼻子下并删除。数据包处理器将检查第一个节点并尝试锁定它,如果它锁定了它,那么它将进行处理,然后解锁它,获取下一个节点,然后删除第一个节点。这种序列化方式仅限于数据包处理器赶上套接字流类的时间

所以现在我的问题是,在我开始实际实施之前,这听起来是个好主意吗?我在一个普通的测试中试过,它似乎工作正常,我想不出有什么严重的问题,只要我实现异常处理并小心释放我分配的任何内存,但是如果有人能想到我忽略的这个想法的任何问题,我会很感激你的输入。另外,我也很感激任何人提出的任何其他建议,无论是作为替代方案,还是可能使这个想法更好地发挥作用的建议


提前谢谢

看看这篇文章,它是关于多个消费者的,但仍然很精彩:


我认为你的建议行不通。请记住,从链接列表中删除节点时,需要更新指向已删除节点的其他节点。类似地,添加节点时,还需要更新其他节点以指向新节点。因此,仅仅锁定被删除或添加的节点是不够的


虽然有无锁队列,但它们很难得到正确的结果。例如,请查看文章的初始注释,其中描述了使已发布的算法正常工作所需的额外工作。

即使您将其称为链表,但实际上这是一个队列

如果您愿意使用固定大小的缓冲区,则可以实现单生产者单消费者无锁队列。这使您可以控制内存使用,但如果使用者的速度不够快,则会让生产者等待

除了这一点,你的设计看起来还不错;与无锁替代方案相比,它可能更容易正确实现


一定要记住有一个终止条件(例如,在
下一个
字段中有一个空指针),这样生产者可能会向消费者发出信号,表示没有更多的事情要处理。

这个实现对我来说有三件事:

  • 很容易出现死锁,因为insert和delete需要同时锁定多个互斥锁,而您不能同时锁定多个互斥锁。可以,但需要在互斥体周围放置互斥体
  • 太容易腐败了。导致僵局的问题也可能导致腐败
  • 慢点,慢点,慢点。想想你那可怜的名单。每一步包括一个解锁、一个锁定、另一个解锁和另一个锁定。我们必须非常小心地走,伙计,这会很贵的。是否按正确顺序锁定和解锁每个项目?哎哟
这看起来像是一个过早优化和过早悲观并行运行的案例。是什么驱动了这种架构


我建议先从简单的解决方案开始。每次你想碰它的任何部分时,都要把它锁起来。看看这会不会给你带来麻烦。如果没有,问题就解决了。如果是这样,下一步就是从互斥锁切换到读写锁。只有一个,不是无数个。现在,您必须考虑一下您想要的是共享锁还是独占锁。如果您对常量的正确性一直很认真,请尝试对常量方法使用共享锁(读锁),对非常量方法使用独占锁(写锁)。

Hmm。。为什么要用如此复杂的方法来解决一个常见的问题?有很多生产者-消费者队列类——选择一个有效的引用/指针/整数大小的类(即无数据复制)

从流中获取字节,直到根据协议组装了“数据包对象”。将packet对象引用推到队列上,并立即新建()另一个对象以用于下一个数据包。数据包处理器使用队列中的数据包对象

队列仅在将对象引用推送到/弹出队列所需的时间内被锁定。套接字/流回调正在组装的数据包对象和数据包处理器正在处理的数据包对象总是不同的,因此不需要锁定

试图对已经在队列中的对象(或类似队列的链表)进行操作,对我来说简直是一场噩梦(其他海报似乎也同意)。你需要这样做还有其他原因吗

Rgds, 马丁

李连杰