进程间通信(IPC)

进程间通信的五种方式:
1.管道(有名管道,无名管道)
2.信号(signal)
3.消息队列
4.共享内存
5.信号量一.管道(有名管道,无名管道)
无名管道:只能在父进程与子进程之间通信
管道的读写其实就是文件的读写操作

void ReadData(int fd)
{
    int ret;
    char buf[32] = {0};
    while (1)
    {
        ret = read(fd, buf, sizeof(buf));
        if (!strcmp(buf, "bye"))
        {
            break;
        }
        printf("read from pipe : %s\n", buf);
        memset(buf, 0, sizeof(buf));
    }
    close(fd);
}
void WriteData(int fd)
{
    int ret;
    char buf[32] = {0};
    while (1)
    {
        scanf("%s", buf);
        ret = write(fd, buf, strlen(buf));
        if (!strcmp(buf, "bye"))
        {
            break;
        }
        memset(buf, 0, sizeof(buf));
    }
    close(fd);
}
无名管道的创建有两个数组,fd[0]读数据,fd[1]写数据
int main()
{
    int ret, fd[2] = {0};
    pid_t pid;
    ret = pipe(fd);   //创建一个无名管道
    if (-1 == ret)
    {
        perror("pipe");
        exit(1);
    }
    pid = fork();    
    if (-1 == pid)
    {
        perror("fork");
        exit(1);
    }
    else if (0 == pid)
    {
        close(fd[1]);       //关闭写端口
        ReadData(fd[0]);    //fd[0]读数据
    }
    else
    {
        close(fd[0]);       //关闭读端口
        int status;
        WriteData(fd[1]);   //fd[1]写数据
        wait(&status);
    }

    return 0;
}


有名管道:可以在不同的两个进程间通信

写数据.C文件
int main()
{
    int ret, fd;
    char buf[32] = {0};    //管道写数据

    fd = open("fifo.tmp", O_WRONLY);
    if (-1 == fd)
    {
        perror("open");
        exit(1);
    }

    while (1)
    {
        scanf("%s", buf);
        ret = write(fd, buf, strlen(buf));
        if (-1 == ret)
        {
            perror("read");
            exit(1);
        }

        if (!strcmp(buf, "bye"))
        {
            break;
        }

        memset(buf, 0, sizeof(buf));
    }

    close(fd);

    return 0;
}


读数据.C文件
int main()
{
    int ret, fd;
    char buf[32] = {0};    //从管道读取数据

    ret = mkfifo("fifo.tmp", 666);  //创建有名管道
    if (ret == -1)
    {
        perror("mkfifo");
        exit(1);
    }

    fd = open("fifo.tmp", O_RDONLY);
    if (-1 == fd)
    {
        perror("open");
        exit(1);
    }

    while (1)
    {
        ret = read(fd, buf, sizeof(buf));
        if (-1 == ret)
        {
            perror("read");
            exit(1);
        }

        if (!strcmp(buf, "bye"))
        {
            break;
        }

        printf("%s\n", buf);

        memset(buf, 0, sizeof(buf));
    }

    close(fd);

    unlink("fifo.tmp");  //使用完删除管道文件

    return 0;
}

二.信号(signal)
相关函数:
1.kill
2.raise(只能给自己发信号)
3.signal(signum,handler)
4.alarm

函数signal(signum,handler)的使用:
void print(int num)  //num 信号的值
{
    printf("helloworld! %d \n", num);
}

int main()
{
    signal(9, SIG_IGN);  //当前进程收到信号2的时候,执行print函数

    while (1);
    return 0;
}

函数alarm的使用:
void print(int num)
{
    alarm(1);
    printf("helloworld\n");
}

int main()
{
    alarm(1);
    signal(SIGALRM, print);

    while (1);

    return 0;
}

三.消息队列

发送.C文件
#define MSGKEY   1234

struct msgbuf {
    long mtype;     /* message type, must be > 0 */
    char mtext[64];  /* message data */
};

int main()
{
    struct msgbuf mbuf;
    int ret;

    int msgid = msgget(MSGKEY, IPC_CREAT | IPC_EXCL);
    if (-1 == msgid)
    {
        perror("msgget");
        exit(1);
    }

    pid_t pid = fork();
    if (-1 == pid)
    {
        perror("fork");
        exit(1);
    }
    else if (0 == pid)    //子进程发送
    {
        while (1)
        {
            memset(&mbuf, 0, sizeof(mbuf));
    
            mbuf.mtype = 1;   //消息类型
            scanf("%s", mbuf.mtext);

            ret = msgsnd(msgid, &mbuf, sizeof(mbuf.mtext), 0);
            if (-1 == ret)
            {
                perror("msgsnd");
                exit(1);
            }

            if (!strcmp(mbuf.mtext, "bye"))
            {
                mbuf.mtype = 2;
                msgsnd(msgid, &mbuf, sizeof(mbuf.mtext), 0);
                break;
            }
        }
    }
    else                 //父进程接收
    {
        while (1)
        {
            memset(&mbuf, 0, sizeof(mbuf));
        
            ret = msgrcv(msgid, &mbuf, sizeof(mbuf.mtext), 2, 0);
            if (-1 == ret)
            {
                perror("msgrcv");
                exit(1);
            }

            if (!strcmp(mbuf.mtext, "bye"))
            {    
                kill(pid, 2);
                break;
            }
            
            printf("\t\t\t%s\n", mbuf.mtext);

            memset(&mbuf, 0, sizeof(mbuf));
        }
    }

    sleep(1);
    msgctl(msgid, IPC_RMID, NULL);

    return 0;
}

接收.C文件
#define MSGKEY   1234

struct msgbuf {
    long mtype;     /* message type, must be > 0 */
    char mtext[64];  /* message data */
};

int main()
{
    struct msgbuf mbuf;
    int ret;

    int msgid = msgget(MSGKEY, 0);
    if (-1 == msgid)
    {
        perror("msgget");
        exit(1);
    }

    pid_t pid = fork();
    if (-1 == pid)
    {
        perror("fork");
        exit(1);
    }
    else if (0 == pid)    //子进程发送
    {
        while (1)
        {
            memset(&mbuf, 0, sizeof(mbuf));
    
            mbuf.mtype = 2;   //消息类型
            scanf("%s", mbuf.mtext);

            ret = msgsnd(msgid, &mbuf, sizeof(mbuf.mtext), 0);
            if (-1 == ret)
            {
                perror("msgsnd");
                exit(1);
            }

            if (!strcmp(mbuf.mtext, "bye"))
            {
                mbuf.mtype = 1;
                msgsnd(msgid, &mbuf, sizeof(mbuf.mtext), 0);
                break;
            }
        }
    }
    else                 //父进程接收
    {
        while (1)
        {
            memset(&mbuf, 0, sizeof(mbuf));
        
            ret = msgrcv(msgid, &mbuf, sizeof(mbuf.mtext), 1, 0);
            if (-1 == ret)
            {
                perror("msgrcv");
                exit(1);
            }

            if (!strcmp(mbuf.mtext, "bye"))
            {
                kill(pid, 2);
                break;
            }
            
            printf("\t\t\t%s\n", mbuf.mtext);

            memset(&mbuf, 0, sizeof(mbuf));
        }
    }

    return 0;
}


 

四.共享内存+信号量

//从共享内存中读:
#define SHMKEY   1234
#define SHMSIZE  4096       //以页为单位分配共享内存
#define SEMKEY   1234

union semun {
    int              val;    /* Value for SETVAL */
    struct semid_ds *buf;    /* Buffer for IPC_STAT, IPC_SET */
    unsigned short  *array;  /* Array for GETALL, SETALL */
    struct seminfo  *__buf;  /* Buffer for IPC_INFO(Linux specific) */
};

void sem_p(int semid)
{
    int ret;
    struct sembuf sbuf;

    sbuf.sem_num = 0;      //第一个 从0开始
    sbuf.sem_op = -1;      //p操作
    sbuf.sem_flg = SEM_UNDO;  

    ret = semop(semid, &sbuf, 1);
    if (-1 == ret)
    {
        perror("semop");
        return;
    }
}

void sem_v(int semid)
{
    int ret;
    struct sembuf sbuf;

    sbuf.sem_num = 0;      //第一个 从0开始
    sbuf.sem_op = 1;      //v操作
    sbuf.sem_flg = SEM_UNDO;  

    ret = semop(semid, &sbuf, 1);
    if (-1 == ret)
    {
        perror("semop");
        return;
    }
}

int main()
{
    int shmid, semid, ret;
    void *shmaddr;
    int count = 0;

    shmid = shmget(SHMKEY, SHMSIZE, IPC_CREAT | IPC_EXCL);   //创建共享内存
    if (-1 == shmid)
    {
        perror("shmget");
        exit(1);
    }

    semid = semget(SEMKEY, 1, IPC_CREAT | IPC_EXCL);    //创建信号量
    if (semid == -1)
    {
        perror("semget");
        exit(1);
    }

    union semun unsem;
    unsem.val = 1;    //初始化成二值信号量
    ret = semctl(semid, 0, SETVAL, unsem);    //初始化信号量
    if (-1 == ret)
    {
        perror("semctl");
        exit(1);
    }

    shmaddr = shmat(shmid, NULL, 0);    //映射到虚拟地址空间
    if (NULL == shmaddr)
    {
        perror("shmat");
        exit(1);
    }

    *(int *)shmaddr = count;       //数据写到共享内存

    while (1)
    {
        sem_p(semid);             //p操作  拔钥匙
        count = *(int *)shmaddr;     //读取数据
        usleep(100000);
        if (count >= 100)
        {
            break;
        }

        printf("Process A : count = %d\n", count);

        count++;

        *(int *)shmaddr = count;    //写回共享内存
        sem_v(semid);           //v操作  加一操作  插钥匙
    }

    shmdt(shmaddr);               //解除映射
    shmctl(shmid, IPC_RMID, NULL);

    semctl(semid, 0, IPC_RMID);
    return 0;
}

//从共享内存中写:
#define SHMKEY   1234
#define SHMSIZE  4096       //以页为单位分配共享内存
#define SEMKEY   1234

union semun {
    int              val;    /* Value for SETVAL */
    struct semid_ds *buf;    /* Buffer for IPC_STAT, IPC_SET */
    unsigned short  *array;  /* Array for GETALL, SETALL */
    struct seminfo  *__buf;  /* Buffer for IPC_INFO(Linux specific) */
};

void sem_p(int semid)
{
    int ret;
    struct sembuf sbuf;

    sbuf.sem_num = 0;      //第一个 从0开始
    sbuf.sem_op = -1;      //p操作
    sbuf.sem_flg = SEM_UNDO;  

    ret = semop(semid, &sbuf, 1);
    if (-1 == ret)
    {
        perror("semop");
        return;
    }
}

void sem_v(int semid)
{
    int ret;
    struct sembuf sbuf;

    sbuf.sem_num = 0;      //第一个 从0开始
    sbuf.sem_op = 1;      //v操作
    sbuf.sem_flg = SEM_UNDO;  

    ret = semop(semid, &sbuf, 1);
    if (-1 == ret)
    {
        perror("semop");
        return;
    }
}

int main()
{
    int shmid, semid, ret;
    void *shmaddr;
    int count = 0;

    shmid = shmget(SHMKEY, SHMSIZE, 0);   //创建共享内存
    if (-1 == shmid)
    {
        perror("shmget");
        exit(1);
    }

    semid = semget(SEMKEY, 1, 0);    //创建信号量
    if (semid == -1)
    {
        perror("semget");
        exit(1);
    }

    shmaddr = shmat(shmid, NULL, 0);    //映射到虚拟地址空间
    if (NULL == shmaddr)
    {
        perror("shmat");
        exit(1);
    }

    while (1)
    {
        sem_p(semid);             //p操作  拔钥匙
        count = *(int *)shmaddr;     //读取数据
        usleep(100000);
        if (count >= 100)
        {
            break;
        }

        printf("Process B : count = %d\n", count);

        count++;

        *(int *)shmaddr = count;    //写回共享内存
        sem_v(semid);           //v操作  加一操作  插钥匙
    }

    shmdt(shmaddr);               //解除映射
    return 0;
}

猜你喜欢

转载自blog.csdn.net/sinat_39440759/article/details/81840316