在linux编程中通过管道在进程之间发送链表结构的最佳方法是什么

时间:2011-03-08 00:58:52

标签: c linux linked-list ipc pipe

我尝试在来自同一父级的子进程之间发送链表。 Child1需要在列表中找到第一个素数并将其删除,然后将其倍数发送给Child2。 Child2执行相同操作,它发送到Child3,ChildN执行相同操作并发送到Child1。但是,我尝试在两者之间发送地址数据而不是所有数字,但这是一种正确的方法,因为我可能会强制我的子进程进入另一个地址空间。那么你想到的最好的方式是什么,或者用其他方式代替发送地址?

4 个答案:

答案 0 :(得分:2)

您还可以使用System V共享内存(查看shmat)或mmap等函数来在进程之间共享内存。 Boost.Interprocess有一个围绕这些调用的C ++包装器,这样您就可以直接在共享内存中创建链接列表而无需复制。

答案 1 :(得分:1)

我假设您正在尝试使用多处理来实现Eratothenes筛选。除非我误解你所描述的内容,否则你的算法可以得到改进。您描述的是一个系统,其中将一个数字列表传递给子进程,该进程在将列表的其余部分交给下一个子进程之前检查所有值。

我会将算法实现为流程管道

Generator -> [Prime2] -> Prime3 -> Prime5 -> Prime7 -> ... PrimeP

下一个Prime流程由链上的最后一个流程创建。因此,当生成8时,它会被Prime2过滤掉并丢弃。当发送9时,它被传递给Prime2,Prime2将它传递给Prime3,Prime3将它丢弃。然后将10删除2,并且通过整个链传递11,并且因为Prime7在它之后的链中没有链接,所以它以11作为参数分配新进程。 Prime2应该像生成它们一样快地消耗值。当Prime 2计算20时,Prime3计算19,依此类推。 (优化:从实现视图中很大程度上不需要Prime2。)

当进程PrimeP创建新进程PrimeN时,父进程创建2个管道,一个用于写入新进程,另一个用于从新进程读取。然后,每个非终端进程节点将具有总共4个管道:两个通向/来自后继节点,两个通向/来自前任节点。可以关闭每个节点的未使用端,但这不是绝对必要的。

这个算法很好,因为管道阻塞读取,直到可以读取一个值。这些数字可以通过管道作为二进制数据发送:

read(parent, &value, sizeof(value))

从上一个过程中读取数据和

write(stdout, &value, sizeof(value))

将数据写入下一个链接。

当生成最后一个数字时,可以通过多种方式暂停链:

  1. 向下传递PoisonPill(例如,值0或其他一些无效数字)。从管道读取时,这可以很好地处理块。
  2. SIGTERM将发送到进程组中的所有进程。
  3. SIGTERM像PoisonPill一样在链中传递(可能效率不如2)。
  4. 如果生成器需要收集所有值,那么当发送PoisonPill时,可以使用另一组管道将它们发送回链中;第二个PoisonPill也可以用作某种控制。

    这有一些问题:

    1. 很多动作都是由前几个素数处理的。
    2. 有很多等待。
    3. 系统可以处理的实际进程数有一个上限。如果您使用的是Haskell之类的东西,这不是问题,但它适用于C。
    4. 使用了很多管道。价值回报的第二组管道可以是shmem,也可以是共享的fifo等。
    5. 大多数机器都有少量处理器......只有少数可以同时运行。解决此问题的一种方法是限制线程数,但每个进程管理多个数字。在这种情况下,您可能希望一次向每个PrimeProcessor发送一个数字块数组。处理器将所有非素数值归零,并将剩余的列表(数组)返回给父级。然后,父级将这些素数分配给PrimeProcessor(此时返回的值不能保证为素数;可能必须进行进一步的分析)并发送一批新的整数。
    6. 要回答你的问题,就我所知,发送链表是没有意义的。你将把它们一个接一个地发送到链中,或者至少作为一个数组发送。

答案 2 :(得分:0)

将索引发送到列表而不是指针,或者将列表压缩成数组并发送它。

(听起来你正在实施Eratothenes的Sieve,无论如何它在阵列上工作得更快。)

答案 3 :(得分:0)

如果您正在使用管道,则通过不将该条目写入管道来“删除”条目。所以不要担心从列表中删除数据,只要考虑是否应该将从输入管道读取的条目写入输出管道。