Linux学习之——Linux进程通信

Linux进程通信


无名管道主要用于有亲缘关系的进程通信,其位于外存区域,但在文件系统中不可见。在实际应用中,进程通信往往发生在无关进程之间,此种情形下,若仍想使用管道,则必须使用有名管道,也称命名管道或FIFO文件。这种类型的管道在文件系统中可见,创建时需要指定具体路径和文件名,管道创建之后,可用ls命令查看。

在终端中命令行中创建有名管道的方法是使用mkfifo命令,如在/tmp目录下创建名为fifoName的有名管道文件,执行下面命令,该命令完成后,可转到相应路径下使用ls命令查看:
# mkfifo /tmp/fifoName
呵呵,FIFO创建好了,我们就可以尝试使用了。首先,创建两个读写进程,其中一个放在后台执行。
# echo "Hello, FIFO!" > /tmp/fifoName &
该命令显示的结果为
[1] 6242
该结果中的6242为后台运行进程的PID号,该数值不一定,根据系统分配的PID号会有相应的值。
然后,创建读取进程,读取写入进程所写入的信息。
# cat < /tmp/fifoName
该命令显示的结果为
Hello, FIFO!
[1]+ Done                    echo "Hello, FIFO!" >/tmp/fifoName
说明两个进程已同时完成各自的工作。

从上面的例子可以看出,FIFO完成了进程通信任务,而且读写两进程是同时完成工作的。操作系统理论指出,对共享区域的操作需要有互斥机制,这种互斥机制在Linux FIFO操作中的具体表现就是操作进程的阻塞。上面的例子中,写进程的操作被放在了后台,所以无法看到阻塞的直接效果,而是输出了一个后台运行的进程号就被阻塞在了后台,直到读进程开始操作时,FIFO中的数据被传递给读进程并显示出来,同时,写进程解除阻塞,同时结束。若想看到阻塞的直接效果,只需要在创建写进程时,不将其放在后台即可,此时的现象为命令行呈现假死机,即进程阻塞状态。
根据例子进行归纳后不难得出结论,只有FIFO两端都有进程工作时,进程才不会阻塞,否则,一端的进程一定会阻塞等待,直至另一进程前来进行操作。

在程序中使用有名管道时,需要用mkfifo系统调用创建FIFO文件,其函数原型为:
int mkfifo(const char *filename, mode_t mode)
该系统调用的功能是创建名为filename的FIFO文件,该文件具有mode访问模式,该mode为一代码,与chmod命令中指定的mode代码含义相同。
FIFO文件创建完成后,要使用open系统调用打开该文件方可使用,open函数原型为:
int open(const char *path, int oflags)
其中,path参数指定文件的具体路径和文件名,oflags参数指定了打开方式,传统打开方式有O_RDONLY、O_WRONLY和O_RDWR三种,而对于FIFO文件来说,O_RDWR方式不可用,因此,若想实现进程之间的双向通信,需要使用两条管道,即创建两个FIFO文件方可进行。此外,还有另外一个辅助的O_NONBLOCK标志常量,使用时与O_RDONLY或O_WRONLY进行逻辑或运算后作为oflags参数值,若使用该标志,则将以非阻塞方式打开,否则,默认为使用阻塞方式打开。
FIFO文件打开后,就可以使用read/write系统调用进行读写了,可以看出,FIFO文件将进程间通信映射为对文件的读写。read/write系统调用的函数原型如下:
size_t read(int fildes, const void *buf, size_t nbytes)
size_t write(int fildes, const void *buf, size_t nbytes)
这两个函数的返回值是进程之间传输的字节数,参数fildes为文件描述符,buf为通信缓冲区,nbytes为需要传输的字节数。这两个函数的功能为将buf中的前nbytes数据读出/写入fildes文件描述符所指代的文件进行通信交互。FIFO使用完毕后,要使用close系统调用关闭FIFO文件通信,使用unlink系统调用删除FIFO文件。

下面给出一个有意义的例子,使用有名管道(FIFO文件)实现一个进程间通信的模板类。

// FifoCommunication.h
#ifndef FIFO_COMMUNICATION_H_
#define FIFO_COMMUNICATION_H_

#include<iostream>
#include<iomanip>
#include<stdio.h>
#include<fcntl.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/stat.h>
#include<sys/types.h>

enum FifoResult { TRANSPORT_SUCCESS, TRANSPORT_FAILURE, CREATE_FAILURE };
const FIFO_NAME_MAX_LENGTH = 256;

template <class MESSAGE_TYPE>
class FifoCommunication
{
    public:
        FifoCommunication(char*, char*);
        ~FifoCommunication();
        FifoResult Read(MESSAGE_TYPE*, int, int*);
        FifoResult Write(MESSAGE_TYPE*, int, int*);
    protected:
        char fifoNameRead[FIFO_NAME_MAX_LENGTH];
        char fifoNameWrite[FIFO_NAME_MAX_LENGTH];
        MESSAGE_TYPE msgReadTempStore;
        MESSAGE_TYPE msgWriteTempStore;
};

#endif

// FifoCommunication.cpp
#include "FifoCommunication.h"

template <class MESSAGE_TYPE>
FifoCommunication<MESSAGE_TYPE>::FifoCommunication(char *fifoRead, char *fifoWrite)
{
    strcpy(fifoNameRead, fifoRead);
    strcpy(fifoNameWrite, fifoWrite);

    umask(0);
    if(mkfifo(fifoNameRead, 0777) == -1 && mkfifo(fifoNameWrite, 0777) == -1)
    {
        std::cerr<<std::endl<<"FIFO Creation Error!"<<std::endl;
        exit(CREATE_FAILURE);
    }
}

template <class MESSAGE_TYPE>
FifoCommunication<MESSAGE_TYPE>::~FifoCommunication()
{
    unlink(fifoNameRead);
    unlink(fifoNameWrite);
}

template <class MESSAGE_TYPE>
FifoResult FifoCommunication<MESSAGE_TYPE>::Read(MESSAGE_TYPE *msgBuffer, int nBufferSize, int *pBytesTransport)
{
    int FifoFd, ReadRes;

    bzero((char*)&msgReadTempStore, sizeof(msgReadTempStore));

    FifoFd = open(fifoNameRead, O_RDONLY);
    if(FifoFd == -1)
    {
        *pBytesTransport = 0;
        return TRANSPORT_FAILURE;
    }
    else
    {
        ReadRes = read(FifoFd, (char*)&msgReadTempStore, nBufferSize);
        if(ReadRes == -1)
        {
            (void)close(FifoFd);
            *pBytesTransport = 0;
            return TRANSPORT_FAILURE;
        }
        else
        {
            (void)close(FifoFd);

            *pBytesTransport = ReadRes;
            memcpy((char*)msgBuffer,(char*)&msgReadTempStore,ReadRes);

            return TRANSPORT_SUCCESS;
        }
    }
}

template <class MESSAGE_TYPE>
FifoResult FifoCommunication<MESSAGE_TYPE>::Write(MESSAGE_TYPE *msgData, int nMessageSize, int *pBytesTransport)
{
    int FifoFd, WriteRes;

    bzero((char*)&msgWriteTempStore, sizeof(msgWriteTempStore));
    memcpy((char*)&msgWriteTempStore,(char*)msgData,nMessageSize);

    FifoFd = open(fifoNameWrite, O_WRONLY);
    if(FifoFd == -1)
    {
        *pBytesTransport = 0;
        return TRANSPORT_FAILURE;
    }
    else
    {
        WriteRes = write(FifoFd, (char*)&msgWriteTempStore, nMessageSize);
        if(WriteRes == -1)
        {
            (void)close(FifoFd);
            *pBytesTransport = 0;
            return TRANSPORT_FAILURE;
        }
        else
        {
            (void)close(FifoFd);
            *pBytesTransport = WriteRes;
            return TRANSPORT_SUCCESS;
        }
    }
}

--------转贴自morre的文章
 

你可能感兴趣的:(linux,工作,Class,Path,任务,终端)