通过使用UNIX管道进行进程同步,我们可以导致饥饿吗? 例如:
void pipesem_wait(struct pipesem *sem)
{
char onebyte = 'A';
if ( read( sem->rfd, &onebyte, sizeof( onebyte ) ) != sizeof( onebyte ) ) {
perror( "read from pipe" );
exit( 1 );
}
}
这是我们从管道中读取的方式.. 当多个进程想要从这个管道中读取时,是否确定所有请求都将以特定(例如FIFO)的顺序处理,或者甚至可能永远不会发生,仍有可能出现饥饿?
答案 0 :(得分:1)
您无法保证哪些读取过程会读取数据,但您可以保证其中只有一个读取每个字节。管道实际上只是内核中的共享缓冲区,具有不同的文件句柄来读取和写入 - 如果多个进程共享这些句柄,则由调度程序决定哪一个获取数据。
因此,如果你的意思是饥饿,因为在一个或多个进程中不会读取任何数据,这很可能 - 如果数据写得足够慢以至于一个进程可以像写入一样快地使用它,那么其他进程可能看不到任何数据。另一方面,它可能在所有进程中循环 - 它只取决于调度的发生方式。你不能依赖这两种情况,行为可能取决于Unix的味道,甚至是那种味道的版本以及它运行的硬件。
但是,您可以依赖所有正在使用的数据而不会丢失数据,并且您可以依赖于按FIFO顺序读取的数据。但是,假设写入"ABC"
并且进程1读取它,然后写入"DEF"
并且进程2读取它。无法保证这些进程将被安排,以便进程1在进程2之前完成对其输入的处理。因此,尽管从管道读取数据的顺序是FIFO,但之后再次取决于如何安排进程。
正如下面的第一个评论者指出的那样,值得一提的是,只要您在write()
以下的PIPE_BUF
数据下写入limits.h
对管道的调用是原子的(在我的Linux上是512字节)例如,系统 - 检查write()
中的等效项。这保证了数据块不会与写入同一管道的任何其他进程的数据交错。如果超过此限制,则标准不会指定pthread_cond_broadcast()
是否为原子。还要记住,对于大块数据,您可能会得到一个部分写入,您应该始终处理。有关详细信息,请参阅the SO question and answer that the commenter linked。
但是,您似乎一次只读取一个字节的数据,所以我猜测您一次只能写一个字节并将其用作某种进程同步机制。您可能想考虑使用带有pthreads条件变量的共享内存,这可以是实现相同目标的更优雅方式 - 我有一些旧的演示代码,我put online here。
注意:如果可移植性对您很重要,那么您可能希望坚持管道 - 我怀疑他们更有可能在最广泛的平台上工作。 pthreads方法应该是相当便携的,但共享内存可能不那么容易。
简而言之,如果您使用它来从池中唤醒工作进程而您不关心使用哪个进程,那么管道作为IPC机制可以正常工作。但是,如果您希望唤醒特定进程,则需要为每个工作者或其他一些机制使用管道。例如,使用pthreads条件变量,您可以通过调用pthread_cond_signal()
而不是{{1}}来唤醒每个进程。
这会回答你的问题吗?