IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 系统运维 -> Linux进程间通信 -> 正文阅读

[系统运维]Linux进程间通信

进程间通信

1.管道

1.方法
   #include <unistd.h>

   int pipe(int pipefd[2]);

管道是半双工的,只能在具有公共祖先的进程间使用。

pipefd[2]:传入大小为2的int数组,返回两个文件描述符,pipefd[0]为读端,pipefd[1]为写端。

2.实例

1.创建一个管道,用于父子进程间数据传输。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <wait.h>
#include <string.h>

#define BUF_SIZE 20

int main(int argc, char const *argv[])
{
    int pipefd[2];
    pid_t pid;
    int err;
    char buf[BUF_SIZE];
    err = pipe(pipefd);
    if(err < 0){
        perror("pipe()");
        exit(1);
    }
    pid = fork();
    if(pid < 0){
        perror("fork");
        exit(1);
    }
    if(pid > 0){//parent
        close(pipefd[0]);//父进程关闭读端
        write(pipefd[1], "Hello\n", 7);//往管道写端写入数据
        waitpid(pid, NULL, 0);//0,表示父进程等待子进程终止
    }else{
        close(pipefd[1]);//子进程关闭写端
        read(pipefd[0], buf, BUF_SIZE);//从管道读端读出数据
        puts(buf);
    }
    exit(0);
}

2.使用管道实现父子进程间同步,如顺序输出abababab。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <wait.h>
#include <string.h>

static int fd_c[2], fd_p[2];

static int tell_wait()
{
    if (pipe(fd_c) < 0 || pipe(fd_p) < 0)
        return -1;
    return 0;
}

static void wait_child()
{
    char c;
    //读子进程管道,如果管道中没有数据,父进程将会阻塞在这儿,直到子进程往管道中写入数据
    if (read(fd_c[0], &c, 1) != 1)
    {
        perror("read fd_c");
        exit(1);
    }
    if (c != 'c')
    {
        fprintf(stderr, "wait child: incorrect data.\n");
    }
}

static void tell_parent()
{
    //往子进程管道中写入数据,父进程将会解除阻塞
    if (write(fd_c[1], "c", 1) != 1)
    {
        perror("write fd_c");
        exit(1);
    }
}

static void wait_parent()
{
    char c;
    if (read(fd_p[0], &c, 1) != 1)
    {
        perror("read fd_p");
        exit(1);
    }
    if (c != 'p')
    {
        fprintf(stderr, "wait parent: incorrect data.\n");
    }
}

static void tell_child()
{
    if (write(fd_p[1], "p", 1) != 1)
    {
        perror("write fd_p");
        exit(1);
    }
}

int main(int argc, char const *argv[])
{
    int err;
    pid_t pid;
    err = tell_wait();
    int i = 0;
    if (err < 0)
    {
        fprintf(stderr, "tell_wait()\n");
        exit(err);
    }
    pid = fork();
    if (pid < 0)
    {
        perror("fork()");
        exit(1);
    }
    if (pid > 0)
    {
        while (i < 10)
        {
            putchar('a');
            fflush(stdout);//由于标准输出时行缓冲模式,所以每输出一个字节,需要flush一下
            sleep(1);
            tell_child();
            wait_child();
            i++;
        }
        wait(NULL);//等待子进程执行完,回收
        puts("");//打印换行符
    }
    else
    {
        while (i < 10)
        {
            wait_parent();
            putchar('b');
            fflush(stdout);
            sleep(1);
            tell_parent();
            i++;
        }
    }
    return 0;
}
运行结果:
shbj@ubuntu:~/develop/workspace/c/ipc$ ./pipe2
abababababababababab 

2.FIFO

通FIFO文件,不相关的进程也能交换数据。

1.方法
   #include <sys/types.h>
   #include <sys/stat.h>

   int mkfifo(const char *pathname, mode_t mode);

pathname : 指定FIFO文件的创建路径。

mode : FIFO文件权限。

2.实例

1.通过FIFO,将实现文件的复制,并将复制文件中的小写字母转换为大写字母。

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <wait.h>

#define PATH "/tmp/fifo1"
#define BUF_SIZE 1024

static int dest_fd1, sou_fd, fifo_fd;
static int i;
static char buf[BUF_SIZE];

static void write_fun(const char *path)
{
    char c;
    fifo_fd = open(PATH, O_WRONLY);//以只写形式打开管道
    int rang;
    if (fifo_fd < 0)
    {
        perror("open fifo");
        exit(1);
    }
    sou_fd = open(path, O_RDONLY);
    if (sou_fd < 0)
    {
        perror("open source");
        exit(1);
    }
    rang = 'z' - 'Z';
    while ((i = read(sou_fd, &c, 1)) > 0)//从原文件中一个字节一个字节的读出数据
    {
        if (c < 'z' && c > 'a')//判断是否为小写字母
            c -= rang;//转换为大写
        write(fifo_fd, &c, i);//写入管道
    }
    close(fifo_fd);
    close(sou_fd);
}

static void read_fun(const char *path)
{
    fifo_fd = open(PATH, O_RDONLY);//以只读形式打开管道
    if (fifo_fd < 0)
    {
        perror("open fifo");
        exit(1);
    }
    dest_fd1 = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0660);
    if (dest_fd1 < 0)
    {
        perror("open dest");
        exit(1);
    }
    while ((i = read(fifo_fd, buf, BUF_SIZE)) > 0)//从管道中读出数据
    {
        write(dest_fd1, buf, i);//写入目标文件
    }
    close(fifo_fd);
    close(dest_fd1);
}

int main(int argc, char const *argv[])
{
    pid_t pid;
    int err, i;
    if (access(PATH, F_OK) < 0)
    {
        err = mkfifo(PATH, 0660);
        if (err < 0)
        {
            perror("mkfifo()");
            exit(1);
        }
    }
    for (i = 0; i < 2; i++)//创建两个子进程
    {
        if ((pid = fork()) < 0)
        {
            perror("fork()");
            exit(1);
        }
        if (pid == 0)
        {
            if (i == 0){//一号子进程写管道
                sleep(2);
                write_fun(argv[1]);
                exit(0);
            }
            else if (i == 1){//二号子进程读管道
                sleep(2);
                read_fun(argv[2]);
                exit(0);
            }
        }
    }
    //由于父进程没有调用wait()等待回收子进程,所以当父进程退出后,子进程会变成孤儿进程,子进程会被init进程托管。
    return 0;
}

3.消息队列

1.方法
       #include <sys/types.h>
       #include <sys/ipc.h>
//根据一个指定的文件路径,得到一个key,主要是利用文件i_node的唯一性,使key也唯一。
       key_t ftok(const char *pathname, int proj_id);

path:文件路径。

proj_id:相当于一个hash的混淆值,一般传入一个字符。

       #include <sys/types.h>
       #include <sys/ipc.h>
       #include <sys/msg.h>
//根据ftok返回的key,得到id。
       int msgget(key_t key, int msgflg);

key:ftok返回的key;如果是有亲缘关系进程间可以使用IPC_PRIVATE。

msgflg:接收端,使用和文件一样的权限位(如0660),如果消息队列以前不存在需要或上IPC_CREATE(0660 |IPC_CREATE);发送端,一般设为0就好。

       #include <sys/types.h>
       #include <sys/ipc.h>
       #include <sys/msg.h>

       int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);

       ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,
                      int msgflg);

msgp:传输数据的指针。

msgsz:数据的大小,需要减去mtype的大小,sizeof(buf) - sizeof(long);

msgflg:

0:接收端,msgrcv将会阻塞,直到队列中有msgtyp对应的消息;

? 发送端,当消息队列满时,msgsnd将会阻塞,直到有消息被取走。

IPC_NOWAIT:接收端,没有对应消息,msgrcv不等待,立即返回;

? 发送端,当消息队列满时,msgsnd不等待,立即返回。

       #include <sys/types.h>
       #include <sys/ipc.h>
       #include <sys/msg.h>

       int msgctl(int msqid, int cmd, struct msqid_ds *buf);

cmd:IPC_STAT、IPC_SET、IPC_RMID。

buf:如果不关心,可以传NULL。

2.实例

1.两个不相关进程间数据传输。

//头文件
#ifndef MSG1_H__
#define MSG1_H__

#define PATH "/etc/services"
#define PROJ_ID 'a'

struct stu_st
{
    char name[20];
    int math;
    int chinese;
};

struct msg_stu
{
    long mtype;
    struct stu_st st;
};

#endif
//接收端
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
#include <errno.h>

#include "msg1.h"

int main(int argc, char const *argv[])
{
    key_t key;
    int id;
    int err;
    struct msg_stu *stp;
    key = ftok(PATH, PROJ_ID);
    if (key < 0)
    {
        perror("ftok()");
        exit(1);
    }
    id = msgget(key, 0660 | IPC_CREAT);
    if (id < 0)
    {
        perror("msgget()");
        exit(1);
    }
    stp = malloc(sizeof(*stp));
    while((err = msgrcv(id, stp, sizeof(*stp) - sizeof(long), 1, 0)) < 0){
        if(err != EINTR){
            perror("msgrcv()");
            msgctl(id, IPC_RMID, NULL);
            exit(1);
        }
    }
    msgctl(id, IPC_RMID, NULL);
    printf("name: %s, chinese : %d, math : %d\n", \
    stp->st.name, stp->st.chinese, stp->st.math);
    return 0;
}
//发送端
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
#include <errno.h>

#include "msg1.h"

int main(int argc, char const *argv[])
{
    key_t key;
    int id;
    int err;
    struct msg_stu *stp;
    key = ftok(PATH, PROJ_ID);
    if (key < 0)
    {
        perror("ftok()");
        exit(1);
    }
    id = msgget(key, 0);
    if (id < 0)
    {
        perror("msgget()");
        exit(1);
    }
    stp = malloc(sizeof(*stp));
    stp->mtype = 1;
    strcpy(stp->st.name, "zhangsan");
    stp->st.math = 90;
    stp->st.chinese = 80;
    //如果被信号打断在重新发送
    while ((err = msgsnd(id, stp, sizeof(*stp) - sizeof(long), 0)) < 0)
    {
        if (err != EINTR)
        {
            perror("msgrcv()");
            exit(1);
        }
    }
    return 0;
}

4.信号量

1.方法

1.获取信号量列表。

   #include <sys/types.h>
   #include <sys/ipc.h>
   #include <sys/sem.h>

   int semget(key_t key, int nsems, int semflg);

nsems:信号量列表中信号量的个数。

semflg:相当于文件的权限位;亲缘关系的进程(如父子进程)key可为IPC_PRIVATE,semflg可以不或上IPC_CREATE,其余需要,如0660|IPC_CREATE。

2.控制信号量列表。

       #include <sys/types.h>
       #include <sys/ipc.h>
       #include <sys/sem.h>

       int semctl(int semid, int semnum, int cmd, ...);

semid:信号量id。

semnum:哪一个信号量,信号量下标。

cmd:命令,IPC_STAT、IPC_SET、IPC_RMID、GETALL、GETVAL、SETALL、SETVAL。

返回值:根据命令的不同返回值不同。

3.操作信号量列表。

       #include <sys/types.h>
       #include <sys/ipc.h>
       #include <sys/sem.h>

       int semop(int semid, struct sembuf *sops, unsigned nsops);

sops:有如下几个成员

? sem_num,信号量编号;
? sem_op,操作,正数+,负数-;
? sem_flg,选项;

nsops:sops的大小。

2.实例

1.多进程间的顺序累加。

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <fcntl.h>
#include <wait.h>
#include <errno.h>

#define BUFFSIZE 10
#define PROCNUM 20

static int sem_id;
static void P()
{
    struct sembuf buf;
    buf.sem_num = 0;//下标为0的信号量
    buf.sem_op = -1;//信号减1
    buf.sem_flg = 0;//无特殊需求
    while (semop(sem_id, &buf, 1) < 0)//操作信号量列表。总的又几个信号量,只有1个信号量
    {
        if (errno == EINTR || errno == EAGAIN)
            continue;
        perror("semop()");
        exit(1);
    }
}

static void V()
{
    struct sembuf buf;
    buf.sem_num = 0;
    buf.sem_op = 1;//信号加1
    buf.sem_flg = 0;
    while (semop(sem_id, &buf, 1) < 0)
    {
        if (errno == EINTR || errno == EAGAIN)
            continue;
        perror("semop()");
        exit(1);
    }
}

int main(int argc, char const *argv[])
{
    FILE *fp;
    char buf[BUFFSIZE];
    int num;
    int i;
    pid_t pid;
    //key_t key;
    //key = ftok("/etc/services", 'a');//无亲缘关系的进程,需要获取一个key
    //sem_id = semget(key, 1, 0660 | IPC_CREATE);//0660 | IPC_CREATE0660
    sem_id = semget(IPC_PRIVATE, 1, 0660); //无亲缘关系的进程key设为IPC_PRIVATE,获取信号量列表
    if (sem_id < 0)
    {
        perror("semget()");
        exit(1);
    }
    if (semctl(sem_id, 0, SETVAL, 1) < 0)//初始化列表中下标为0的信号量,初始值为1。
    { 
        perror("semctl()");
        exit(1);
    }
    for (i = 0; i < PROCNUM; i++)//创建多个进程,对指定文件中的数据累加
    {
        pid = fork();
        if (pid < 0)
        {
            perror("fork()");
            exit(1);
        }
        if (pid == 0)
        {
            fp = fopen("/tmp/out", "r+");
            if (fp == NULL)
            {
                perror("fopen()");
                exit(1);
            }
            P();//获取信号量,信号量为0时阻塞
            fgets(buf, BUFFSIZE, fp);
            fseek(fp, 0, SEEK_SET);
            num = atoi(buf);
            fprintf(fp, "%d\n", ++num);
            fflush(fp);
            sleep(1);
            V();//归还信号量,信号量+1
            fclose(fp);
            exit(0);
        }
    }
    for (i = 0; i < PROCNUM; i++)
        wait(NULL);//回收子进程
    semctl(sem_id, 0, IPC_RMID);
    return 0;
}
执行结果:
hbj@ubuntu:~/develop/workspace/c/ipc/sem$ echo 10 > /tmp/out
shbj@ubuntu:~/develop/workspace/c/ipc/sem$ ./reciver 
shbj@ubuntu:~/develop/workspace/c/ipc/sem$ cat /tmp/out
30
shbj@ubuntu:~/develop/workspace/c/ipc/sem$ 

5.共享存储

共享存储允许两个或多个进程共享一个给定的存储区。因为数据不需要在客户进程和服务器进程之间复制,所以这是最快的一种IPC。

共享存储与内存映射的区别,共享存储没有相关的文件,共享存储段是内存的匿名段。

1.方法

1.创建共享存储。

       #include <sys/ipc.h>
       #include <sys/shm.h>

       int shmget(key_t key, size_t size, int shmflg);

size:存储区大小。

shmflg:权限位。

返回值:成功返回共享存储id,失败-1。

2.操作共享存储。

       #include <sys/ipc.h>
       #include <sys/shm.h>

       int shmctl(int shmid, int cmd, struct shmid_ds *buf);

cmd:操作命令;IPC_STAT、IPC_SET、IPC_RMID

buf:cmd为IPC_STAT,将对应共享存储的shmid_ds结构,存储在buf指向的结构中;

? cmd为IPC_SET,按照buf指向结构中的值,设置共享存储对应的shmid_ds结构。

3.共享存储连接到调用进程的哪个地址上。

   #include <sys/types.h>
   #include <sys/shm.h>

   void *shmat(int shmid, const void *shmaddr, int shmflg);//shmid_ds中的shm_nattach +1

   int shmdt(const void *shmaddr);//shmid_ds中的shm_nattach -1

shmid:共享存储的id。

shmaddr:指定的地址,一般设为0,由系统自动分配。

shmflg:一般也设为0。

进程中,当共享存储段的操作结束时,调用shmdt与该段分离。注意,调用shmdt并不删除共享存储,只有当某个进程(一般是服务进程)调用了带IPC_RMID命令的shm_ctl特地删除它为止。

2.实例

1.使用共享存储实现不同进程间的数据传输。

#ifndef PROTO_H__
#define PROTO_H__

#define PATH "/etc/services"
#define PROJ_ID 'a'

struct stu_st
{
    char name[20];
    int math;
    int chinese;
};

struct msg_stu
{
    long mtype;
    struct stu_st st;
};

#endif

//接收端
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include "proto.h"

#define PATH "/etc/services"
#define SHM_SIZE 1024

int main(int argc, char const *argv[])
{
    key_t key;
    int shmid, err;
    struct stu_st *stp;
    key = ftok(PATH, 'a');
    if (key < 0)
    {
        perror("ftok()");
        exit(1);
    }
    shmid = shmget(key, SHM_SIZE, 0660 | IPC_CREAT);
    if (shmid < 0)
    {
        perror("shmget()");
        exit(1);
    }
    stp = shmat(shmid, 0, 0);
    if (stp < 0)
    {
        perror("shmat()");
        exit(1);
    }
    sleep(10);
    printf("%s, %d, %d\n", stp->name, stp->chinese, stp->math);
    strcpy(stp->name, "lisi");
    sleep(10);
    err = shmdt(stp);
    if (err < 0)
    {
        perror("shmdt()");
        exit(1);
    }
    err = shmctl(shmid, IPC_RMID, NULL);
    if (err < 0)
    {
        perror("shmctl()");
        exit(1);
    }
    return 0;
}

//发送端
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include "proto.h"

#define PATH "/etc/services"
#define SHM_SIZE 1024

int main(int argc, char const *argv[])
{
    key_t key;
    int shmid, err;
    struct stu_st *stp;
    key = ftok(PATH, 'a');
    shmid = shmget(key, SHM_SIZE, 0660);
    stp = (struct stu_st *)shmat(shmid, 0, 0);
    strcpy(stp->name, "zhangsan");
    stp->chinese = 90;
    stp->math = 95;
    sleep(10);
    printf("%s, %d, %d\n", stp->name, stp->chinese, stp->math);
    err = shmdt(stp);
    return 0;
}

2.改进1程序,实现两个进程间的数据同步,即同时只能有一个进程操作共享存储区。

采用信号量实现同步。

//同步代码
//proto.h
#ifndef PROTO_H__
#define PROTO_H__

#define PATH "/etc/services"
#define PROJ_ID 'a'

struct stu_st
{
    char name[20];
    int math;
    int chinese;
};

struct msg_stu
{
    long mtype;
    struct stu_st st;
};

void sem_init();
void sem_destroy();
void P1();
void V1();

void P2();
void V2();

#endif

//proto.c
#include <stdio.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <errno.h>
#include "proto.h"

static int semid;
void sem_init()
{
    key_t key;
    key = ftok(PATH, PROJ_ID);
    if (key < 0)
    {
        perror("ftok()");
        exit(1);
    }
    //判断信号量是否创建,创建两个信号量,0信号用于接收端,1信号用于发送端
    if ((semid = semget(key, 2, 0660)) < 0)
    {
        semid = semget(key, 2, 0660 | IPC_CREAT);
    }
    if (semid < 0)
    {
        perror("semget()");
        exit(1);
    }
    if (semctl(semid, 0, SETVAL, 0) < 0)//信号量初值都设为0
    {
        perror("semctl()");
        exit(1);
    }
    if (semctl(semid, 1, SETVAL, 0) < 0)
    {
        perror("semctl()");
        exit(1);
    }
}

void sem_destroy(){
    semctl(semid, 0, IPC_RMID);
}

//0信号量,初值为0,接收端进程会阻塞
void P1()
{
    struct sembuf buf;
    buf.sem_num = 0;//0信号
    buf.sem_op = -1;
    buf.sem_flg = SEM_UNDO;
    while (semop(semid, &buf, 1) < 0)
    {
        if (errno == EINTR || errno == EAGAIN)
            continue;
        perror("semop_p1()");
        exit(1);
    }
}
//0信号量+1,唤醒接收端进程
void V1()
{
    struct sembuf buf;
    buf.sem_num = 0;
    buf.sem_op = 1;
    buf.sem_flg = SEM_UNDO;
    while (semop(semid, &buf, 1) < 0)
    {
        if (errno == EINTR || errno == EAGAIN)
            continue;
        perror("semop_v1()");
        exit(1);
    }
}

//1信号量,初值为0,发送端进程会阻塞
void P2()
{
    struct sembuf buf;
    buf.sem_num = 1;
    buf.sem_op = -1;
    buf.sem_flg = SEM_UNDO;
    while (semop(semid, &buf, 1) < 0)
    {
        if (errno == EINTR || errno == EAGAIN)
            continue;
        perror("semop_p2()");
        exit(1);
    }
}
//1信号量+1,唤醒发送端进程
void V2()
{
    struct sembuf buf;
    buf.sem_num = 1;
    buf.sem_op = 1;
    buf.sem_flg = SEM_UNDO;
    while (semop(semid, &buf, 1) < 0)
    {
        if (errno == EINTR || errno == EAGAIN)
            continue;
        perror("semop_v2()");
        exit(1);
    }
}

接收端

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <sys/sem.h>
#include <errno.h>
#include "proto.h"

#define SHM_SIZE 1024

int main(int argc, char const *argv[])
{
    key_t key;
    int shmid, err;
    struct stu_st *stp;
    key = ftok(PATH, 'a');
    if (key < 0)
    {
        perror("ftok()");
        exit(1);
    }
    shmid = shmget(key, SHM_SIZE, 0660 | IPC_CREAT);
    if (shmid < 0)
    {
        perror("shmget()");
        exit(1);
    }
    sem_init();
    stp = shmat(shmid, 0, 0);
    if (stp < 0)
    {
        perror("shmat()");
        exit(1);
    }
    P1();
    printf("%s, %d, %d\n", stp->name, stp->chinese, stp->math);
    strcpy(stp->name, "lisi");
    sleep(5);
    V2();
    err = shmdt(stp);
    if (err < 0)
    {
        perror("shmdt()");
        exit(1);
    }
    P1();
    err = shmctl(shmid, IPC_RMID, NULL);
    if (err < 0)
    {
        perror("shmctl()");
        exit(1);
    }
    sem_destroy();//接收端销毁信号量
    return 0;
}

发送端

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include "proto.h"

#define SHM_SIZE 1024

int main(int argc, char const *argv[])
{
    key_t key;
    int shmid, err;
    struct stu_st *stp;
    key = ftok(PATH, 'a');
    shmid = shmget(key, SHM_SIZE, 0660);
    stp = (struct stu_st *)shmat(shmid, 0, 0);
    sem_init();
    strcpy(stp->name, "zhangsan");
    stp->chinese = 90;
    stp->math = 95;
    sleep(5);
    V1();
    P2();
    printf("%s, %d, %d\n", stp->name, stp->chinese, stp->math);
    err = shmdt(stp);
    V1();
    return 0;
}
  系统运维 最新文章
配置小型公司网络WLAN基本业务(AC通过三层
如何在交付运维过程中建立风险底线意识,提
快速传输大文件,怎么通过网络传大文件给对
从游戏服务端角度分析移动同步(状态同步)
MySQL使用MyCat实现分库分表
如何用DWDM射频光纤技术实现200公里外的站点
国内顺畅下载k8s.gcr.io的镜像
自动化测试appium
ctfshow ssrf
Linux操作系统学习之实用指令(Centos7/8均
上一篇文章      下一篇文章      查看所有文章
加:2022-01-24 11:21:19  更:2022-01-24 11:22:14 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/16 8:45:08-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码