Linux c/c++之IPC进程间通信

简介: 这篇文章详细介绍了Linux下C/C++进程间通信(IPC)的三种主要技术:共享内存、消息队列和信号量,包括它们的编程模型、API函数原型、优势与缺点,并通过示例代码展示了它们的创建、使用和管理方法。

1. IPC定义

IPC技术: 内核进程通信(Inter Process Communication)

2. 共享内存

2.1 共享内存定义

    shm(share memory),在主机上指定一块内存作为进程之间的共享内存, 不同的进程之间可以通过一些方式去访问这块内存。

2.2 shm(共享内存 编程模型)

  1. 创建key ftok函数
  2. 创建共享内存 shmget函数
  3. 挂载共享内存 shmat函数
  4. 卸载共享内存 shmdt函数
  5. 删除共享内存 shmctl函数

2.3 shm的一些函数原型

2.3.1 ftok函数

//头文件
#include <sys/types.h>
#include <sys/ipc.h>
//函数原型
key_t ftok(const char *pathname, int proj_id);

//返回值: 返回值为一个4byte的整数(返回-1失败)
//0--15  bit: pathname的st_ino属性的低16位
//16--23 bit: pathname的st_dev属性的低8位
//24--31 bit: pro_id的低8位

//参数一: 传入一个路径,一般使用当前路径"."
//参数二: 任意的一个整数,因为要做进程间通信,
//那么另一个进程需要与这个数保持一致才能找到对应的ipcid,一般只使用8个bit,因此取值范围在0--255

2.3.2 shmget函数

//头文件
#include <sys/ipc.h>
#include <sys/shm.h>
//函数原型
int shmget(key_t key, size_t size, int shmflg);

//返回值: 返回一个整数(返回-1失败) 

//参数一: ftok函数的返回值
//参数二: 共享的内存大小(byte)(如果数值为1 -- 4096,实际申请4k(一页))
//参数三: 主要与一些标志有关
// IPC_CREAT  不存在共享内存就创建,否则打开
// IPC_EXCL   不存在共享内存才创建,否则错误

2.3.3 shmat函数

//头文件
#include <sys/types.h>
#include <sys/shm.h>
//函数原型
void *shmat(int shmid, const void *shmaddr, int shmflg);

//返回值: 返回申请的共享内存的首地址(返回-1则挂载失败)

//参数一: shmget函数的返回值
//参数二: 一般为0,表示连接到一个由内核选择的可用地址之上
//参数三: 一般为0

2.3.4 shmdt函数

//头文件
#include <sys/types.h>
#include <sys/shm.h>
//函数原型
int shmdt(const void *shmaddr);

//返回值: 成功返回0,失败返回-1
//参数一: shmat函数的返回值

2.3.5 shmctl函数

//头文件
#include <sys/ipc.h>
#include <sys/shm.h>
//函数原型
int shmctl(int shmid, int cmd, struct shmid_ds *buf);

//返回值: 失败返回-1,
//参数一: shmget函数的返回值
//参数二: 设置调用者对共享内存段的权限
// IPC_STAT: 调用者必须对共享内存具有读权限
// IPC_SET: 对shmid_ds 中的某些值做一些修改
// IPC_RMID: 表示销毁某个段
// IPC_INFO: 返回共享内存限制和参数的信息
// SHM_INFO: 返回一个shm_info的结构体
// SHM_STAT: 返回该内存段在内核数组的索引,该数组记录所有共享内存段的信息
// SHM_LOCK: 防止交换共享内存段
// SHM_UNLOCK: 解除防止交换共享内存段
//参数三: 一个指向shmid_ds的结构体指针
struct shmid_ds 
{   struct ipc_perm shm_perm;/*用户权限*/
    size_t shm_segsz;/* segment (bytes)的大小*/
    time_t shm_atime;/*最后连接时间*/
    time_t shm_dtime;/*最后的分离时间时间*/
    time_t ctime;/*上次更改时间*/
    pid_t  shm_cpid;/*创建器的PID*/
    ......
};

2.4 共享内存的优势与缺点

2.4.1 优势

因为两个进程可以使用一段内存, 这就构成了进程之间的双向通信, 无疑传输速率是很快的, 是最快的进程间通信方式。因为不同的进程之间是直接从这一段内存之中存放、读取数据。而且使用共享内存进行通信对数据是没有什么限制的。并且共享内存的生命周期与系统内核的生命周期是一致的。

2.4.2 缺点

共享内存并没有提供同步机制,在一个进程对共享内存进行写操作结束之前,另一个进程是不能对这块共享内存进行同步访问的,因为我们通常想要实现的是多个进程对共享内存的同步访问。

2.5 共享内存示例

使用shmA.c从共享内存中读取数据, shmB.c向共享内存中写入数据, shmctl.c删除共享内存段

2.5.1 共享内存数据读取端

//shmA.c  读取端
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <signal.h>

int* p = NULL;
void hand(){
    //5.卸载功能共享内存
    shmdt(p);
    printf("bye bye!\n");

    exit(0);
}
int main(){
    signal(SIGINT,hand);
    //1.创建key
    key_t key = ftok(".",'m');  //参数二在256之内
    if(-1 == key) printf("create key error:%m\n"),exit(-1);
    printf("create key success!\n");
    //2.创建共享内存   内存单位之页   1页 == 4k
    int shmid = shmget(key,4096,IPC_CREAT);
    if(-1 == shmid) printf("shmget error:%m\n"),exit(-1);
    printf("shmget success!\n");
    //3.挂载共享内存
    p = (int*)shmat(shmid,NULL,0);
    if((int*)-1 == p) printf("shmat error:%m\n"),exit(-1);
    printf("shmat success!\n");
    //4.使用共享内存
    while(1){
        printf("%d\n",*p);
        sleep(1);
    }

    return 0;
}

2.5.2 共享内存数据发送端

//shmB.c  写入端
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <signal.h>

int* p = NULL;
void hand(){
    //5.卸载功能共享内存
    shmdt(p);
    printf("bye bye!\n");

    exit(0);
}
int main(){
    signal(SIGINT,hand);
    //1.创建key
    key_t key = ftok(".",'m');  //参数二在256之内
    if(-1 == key) printf("create key error:%m\n"),exit(-1);
    printf("create key success!\n");
    //2.获取共享内存  
    int shmid = shmget(key,4096,IPC_CREAT);
    if(-1 == shmid) printf("shmget error:%m\n"),exit(-1);
    printf("shmget success!\n");
    //3.挂载共享内存
    p = (int*)shmat(shmid,NULL,0);
    if(NULL == p) printf("shmat error:%m\n"),exit(-1);
    printf("shmat success!\n");
    //4.使用共享内存
    int n = 0;
    while(1){
        *p = n++;
        sleep(1);
    }

    return 0;
}

2.5.3 共享内存段删除端

//shmctl.c  删除共享内存
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>

int main(){
    //1.创建key
    key_t key = ftok(".",'m');  //参数二在256之内
    if(-1 == key) printf("create key error:%m\n"),exit(-1);
    printf("create key success!\n");
    //2.获取共享内存  
    int shmid = shmget(key,4096,IPC_CREAT);
    if(-1 == shmid) printf("shmget error:%m\n"),exit(-1);
    printf("shmget success!\n");

    //3.删除共享内存
    shmctl(shmid,IPC_RMID,NULL);

    return 0;
}

2.5.4 运行结果

shmA读取数据进程端单独运行:

shmA读取数据进程端与shmB写入数据进程端同时运行:

ipcs -m 命令查看当前共享内存信息:

使用shmctl删除当前创建的共享内存段后:

3. 消息队列

3.1 消息队列定义

    msg(message queue), 在主机上指定一个或者多个队列, 一方进程向队列之中放数据, 另一方从队列之中拿东西。

3.2 msg(消息队列 编程模型)

  1. 创建key ftok函数
  2. 创建消息队列 msgget函数
  3. 收发消息 msgrcv 函数 msgsnd 函数
  4. 删除消息队列 msgctl函数

3.3 msg的一些函数原型

3.3.1 ftok函数

//头文件
#include <sys/types.h>
#include <sys/ipc.h>
//函数原型
key_t ftok(const char *pathname, int proj_id);

//返回值: 返回值为一个4byte的整数(返回-1失败)
//0--15  bit: pathname的st_ino属性的低16位
//16--23 bit: pathname的st_dev属性的低8位
//24--31 bit: pro_id的低8位

//参数一: 传入一个路径,一般使用当前路径"."
//参数二: 任意的一个整数,因为要做进程间通信,
//那么另一个进程需要与这个数保持一致才能找到对应的ipcid,一般只使用8个bit,因此取值范围在0--255

3.3.2 msgget函数

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

int msgget(key_t key, int msgflg);

//返回值: 返回一个整数(-1表示失败)
//参数一: ftok函数的返回值
//参数二: 主要是一些标志
// IPC_CREAT  不存在共享内存就创建,否则打开
// IPC_EXCL   不存在共享内存才创建,否则错误

3.3.3 msgrcv函数

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

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

//返回值: (失败返回-1)返回实际复制到mtext数组中的字节数
//参数一: msgget函数的返回值
//参数二: 指向消息缓冲区的指针,此位置用来暂时存储发送和接收的消息,是一个用户可定义的通用结构
    struct msgbuf {
        long mtype;    
        char mtext[1];  //可以是1,也可以是其它数
    };
//参数三: 消息的大小
//参数四: 从消息队列内读取的消息形态。如果值为零,则表示消息队列中的所有消息都会被读取。
//参数五: 用来指明核心程序在队列没有数据的情况下所应采取的行动。如果msgflg和常数IPC_NOWAIT合用,则在消息队列呈空时,不做等待马上返回-1,并设定错误码为ENOMSG。

3.3.4 msgsnd函数

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

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

//返回值: (失败返回-1)成功返回0
//参数一: msgget函数的返回值
//参数二: 指向消息缓冲区的指针,此位置用来暂时存储发送和接收的消息,是一个用户可定义的通用结构
    struct msgbuf {
        long mtype;    
        char mtext[1];  //可以是1,也可以是其它数
    };
//参数三: 消息的大小
//参数四: 用来指明核心程序在队列没有数据的情况下所应采取的行动。如果msgflg和常数IPC_NOWAIT合用,则在msgsnd()执行时若是消息队列已满,则msgsnd()将不会阻塞,而会立即返回-1。当msgflg为0时,msgsnd()及msgrcv()在队列呈满或呈空的情形时,采取阻塞等待的处理模式。

3.3.5 msgctl函数

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

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

//返回值: 失败返回-1,
//参数一: shmget函数的返回值
//参数二: 设置调用者对共享内存段的权限
// IPC_STAT: 调用者必须对共享内存具有读权限
// IPC_SET: 对msqid_ds 中的某些值做一些修改
// IPC_RMID: 表示销毁某个段
// IPC_INFO: 返回共享内存限制和参数的信息
// MSG_INFO: 返回一个msginfo的结构体
// MSG_STAT: 返回该内存段在内核数组的索引,该数组记录所有共享内存段的信息
//参数三: 一个指向msqid_ds 的结构体指针
struct msqid_ds {
               struct ipc_perm msg_perm;     /* 所有权和权限 */
               time_t          msg_stime;    /* 最后一次 msgsnd(2) */
               time_t          msg_rtime;    /* 最后一次 msgrcv(2) */
               time_t          msg_ctime;    /* 最后一次修改的时间*/
               unsigned long   __msg_cbytes; /* 当前队列的字节数(非标准) */
               msgqnum_t       msg_qnum;     /* 当前队列中的消息数 */
               msglen_t        msg_qbytes;   /* 队列允许的最大字节数 */
               pid_t           msg_lspid;    /* 上一次 msgsnd(2) 的PID*/
               pid_t           msg_lrpid;    /* PID of last msgrcv(2) */
           };

3.4 消息队列的优势与缺点

3.4.1 优势

消息队列提供了一种从进程向另一个进程发送一个数据块的方法。每个数据块都被认为是一个类型,接收进程接收的数据块可以有不同的类型值。可以通过发送消息来避免命名管道的同步和阻塞的问题。消息队列与管道不同的是,消息队列是基于消息的,而管道是基于字节流的,且消息队列的读取不一定是先入先出。

3.4.2 缺点

每个数据块有大小限制, 整个操作系统中所有的数据块总大小也有一个限制。

3.5 消息队列演示

3.5.1 消息发送端

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

//发送端进程
struct msgbuf{
    long type;
    char buff[20];
};
int main(){
    struct msgbuf msg;
    //1.创建key
    key_t key = ftok(".",'q');
    if(-1 == key) printf("ftok error:%m\n"),exit(-1);
    printf("ftok success!\n");
    //2. 创建消息队列
    int msgid = msgget(key,IPC_CREAT | 0666);
    if(-1 == msgid) printf("msgget error:%m\n"),exit(-1);
    printf("msgget success!\n");
    //3. 发消息
    int r;
    while(1){
        printf("请输入消息类型:");
        scanf("%ld",&msg.type);
        printf("请输入消息内容:");
        scanf("%s",msg.buff);
        r = msgsnd(msgid,&msg,sizeof(msg),IPC_NOWAIT); //IPC_NOWAIT非阻塞方式
        printf("r: %d\n",r);
    }


    return 0;
}

3.5.2 消息接收端

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>

#define TYPE 2
//接收端进程
struct msgbuf{
    long type;
    char buff[20];
};
int main(){
    struct msgbuf msg;
    msg.type = TYPE;
    //1.创建key
    key_t key = ftok(".",'q');
    if(-1 == key) printf("ftok error:%m\n"),exit(-1);
    printf("ftok success!\n");
    //2. 创建消息队列
    int msgid = msgget(key,IPC_CREAT | 0666);
    if(-1 == msgid) printf("msgget error:%m\n"),exit(-1);
    printf("msgget success!\n");
    //3. 接收消息
    int r;
    while(1){
        memset(msg.buff,0,20);
        r = msgrcv(msgid,&msg,sizeof(msg),TYPE,IPC_NOWAIT);
        printf("r:%d msg:%s type:%ld\n", r, msg.buff, msg.type);
        sleep(1);
    }
    return 0;
}

3.5.3 消息队列删除端

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>

int main(){
    //1.创建key
    key_t key = ftok(".",'q');
    if(-1 == key) printf("ftok error:%m\n"),exit(-1);
    printf("ftok success!\n");
    //2. 创建消息队列
    int msgid = msgget(key,IPC_CREAT | 0666);
    if(-1 == msgid) printf("msgget error:%m\n"),exit(-1);
    printf("msgget success!\n");
    //3. 删除当前消息队列
    msgctl(msgid,IPC_RMID,NULL);


    return 0;
}

3.5.6 运行结果

当发送端的消息类型是type = 2 时, 接收端将消息队列中 type为2的消息取出来处理, type为3的消息仍然在消息队列中

使用命令查看创建的消息队列 (已用字节数是刚刚的type为3的消息)

继续发送一个type为5的消息和一个type为6的消息,发现已用字节数变成了96

删除消息队列后

4. 旗语(信号量)

4.1 旗语(信号量定义)

sem(semaphore), 让多个进程不可能同时访问一块区域

4.2 sem(信号量 编程模型)

  1. 创建key ftok函数
  2. 创建旗语(信号量) semget函数
  3. 初始化旗语(信号量) semctl函数
  4. 使用旗语(信号量) semop函数
  5. 删除旗语(信号量) semctl函数

4.3 sem的一些函数原型

4.3.1 ftok函数

//头文件
#include <sys/types.h>
#include <sys/ipc.h>
//函数原型
key_t ftok(const char *pathname, int proj_id);

//返回值: 返回值为一个4byte的整数(返回-1失败)
//0--15  bit: pathname的st_ino属性的低16位
//16--23 bit: pathname的st_dev属性的低8位
//24--31 bit: pro_id的低8位

//参数一: 传入一个路径,一般使用当前路径"."
//参数二: 任意的一个整数,因为要做进程间通信,
//那么另一个进程需要与这个数保持一致才能找到对应的ipcid,一般只使用8个bit,因此取值范围在0--255

4.3.2 semget函数

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

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

//返回值: 返回一个整数(-1表示失败)
//参数一: ftok函数返回值
//参数二: 创建信号量的个数(一般创建一个)
//参数三: 主要是一些标志
// IPC_CREAT  不存在共享内存就创建,否则打开
// IPC_EXCL   不存在共享内存才创建,否则错误

4.3.3 semop函数

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

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

//返回值: 成功返回0, 失败返回-1
//参数一: semget函数返回值()
//参数二: 信号量的一些信息(用户可更改)
sops[0].sem_num = 0; 信号量的索引
sops[0].sem_op = 0;  加还是减以及加减的值
sops[0].sem_flg = 0; 一般设置为0
//参数三: 操作的次数

4.3.4 semctl函数

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

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

//返回值: 失败返回-1
//参数一: semget函数返回值(信号量的标识id)
//参数二: 信号量的标识,标识使用第几个信号量(从0开始)
//参数三: 一个指向msqid_ds 的结构体指针
// IPC_STAT: 调用者必须对共享内存具有读权限
// IPC_SET: 对semid_ds 中的某些值做一些修改
// IPC_RMID: 表示销毁某个段
// IPC_INFO: 返回共享内存限制和参数的信息
// SEM_INFO: 返回一个seminfo的结构体
// SEM_STAT: 返回该内存段在内核数组的索引,该数组记录所有共享内存段的信息
// GETALL:   获取集合中所有的信号量
// GETNCNT:  返回集合中指定semnum的信号量
// GETPID:   返回指定semnum的sempid的值
// GETVAL:   返回指定semnum的semval的值
// GETZCNT:  返回集合中第一个信号量的semzcnt值
// SETALL:   为集合中所有信号量设置值
// SETVAL:   设置一个信号量的值
//参数四: 缺省参数, union semun类型的指针
 union semun {
               int              val;    /* 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*/
           };

4.4 旗语(信号量)的优势与缺点

4.4.1 优势

节省了打开文件以及关闭文件的时间,数据传输速率提高

4.4.2 缺点

一但被锁定, 在解锁之前出现程序崩溃等问题, 就会导致锁定的信号量无法恢复, 形成永久性的占用, 使用文件操作的方式则不会出现这种情况, 因为在进程退出的时候, 文件就会被关闭, 在该文件描述符上的锁定就会被自动解除。

4.5 旗语(信号量演示)

4.5.1 信号量加端

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>

int main(){
    //1. 创建key
    key_t key = ftok(".",'s');
    if(-1 == key) printf("ftok error:%m\n"),exit(-1);
    printf("ftok success!\n");
    //2. 创建信号量
    int semid = semget(key,1,IPC_CREAT | 0654);
    if(-1 == semid) printf("semget error:%m\n"),exit(-1);
    printf("semget success!\n");

    //3. 使用旗语
    struct sembuf buf;
    buf.sem_num = 0;
    buf.sem_op = 1;     //加
    buf.sem_flg = 0;

    while(1){
        semop(semid,&buf,1); //操作一次
        sleep(1);
    }


    return 0;
}

4.5.2 信号量减端

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>

union semun{
    int val;
    struct semid_ds* buf;
    unsigned short* array;
    struct seminfo* __buf;
};
int main(){
    //1. 创建key
    key_t key = ftok(".",'s');
    if(-1 == key) printf("ftok error:%m\n"),exit(-1);
    printf("ftok success!\n");
    //2. 创建信号量
    int semid = semget(key,1,IPC_CREAT | 0654);
    if(-1 == semid) printf("semget error:%m\n"),exit(-1);
    printf("semget success!\n");
    //3. 初始化信号量
    union semun u;
    u.val = 5;
    semctl(semid,0,SETVAL,u);
    //4. 使用旗语
    struct sembuf buf;
    buf.sem_num = 0;
    buf.sem_op = -1;    //减
    buf.sem_flg = 0;

    int n = 0;
    while(1){
        printf("卖出%d辆!\n",++n);
        semop(semid,&buf,1); //操作一次
    }

    return 0;
}

4.5.3 信号量删除

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <signal.h>

int main(){
    //1. 创建key
    key_t key = ftok(".",'s');
    if(-1 == key) printf("ftok error:%m\n"),exit(-1);
    printf("ftok success!\n");
    //2. 创建信号量
    int semid = semget(key,1,IPC_CREAT | 0654);
    if(-1 == semid) printf("semget error:%m\n"),exit(-1);
    printf("semget success!\n");

    //3. 删除旗语
    semctl(semid,0,IPC_RMID,NULL);

    return 0;
}

4.5.4 运行结果

设置信号量 0 初始值为5, 运行A后,再运行B:

ipcs -s 查看信号量信息:

删除创建的信号量后,ipcs -s 查看信号量信息:

5. 管理IPC的ipc命令簇

5.1 ipcs 查看命令

  1. -m 查看shm(共享内存)
  2. -q 查看msg(消息队列)
  3. -s 查看sem(信号量)

5.2 ipcrm 删除命令

  1. -m 删除shm(共享内存)
  2. -q 删除msg(消息队列)
  3. -s 删除sem(信号量)

注: shm msg sem 都必须先有一个key(key是根据fd来创建的)

相关文章
|
5月前
|
并行计算 Linux
Linux内核中的线程和进程实现详解
了解进程和线程如何工作,可以帮助我们更好地编写程序,充分利用多核CPU,实现并行计算,提高系统的响应速度和计算效能。记住,适当平衡进程和线程的使用,既要拥有独立空间的'兄弟',也需要在'家庭'中分享和并行的成员。对于这个世界,现在,你应该有一个全新的认识。
237 67
|
4月前
|
Web App开发 Linux 程序员
获取和理解Linux进程以及其PID的基础知识。
总的来说,理解Linux进程及其PID需要我们明白,进程就如同汽车,负责执行任务,而PID则是独特的车牌号,为我们提供了管理的便利。知道这个,我们就可以更好地理解和操作Linux系统,甚至通过对进程的有效管理,让系统运行得更加顺畅。
115 16
|
4月前
|
Unix Linux
对于Linux的进程概念以及进程状态的理解和解析
现在,我们已经了解了Linux进程的基础知识和进程状态的理解了。这就像我们理解了城市中行人的行走和行为模式!希望这个形象的例子能帮助我们更好地理解这个重要的概念,并在实际应用中发挥作用。
93 20
|
3月前
|
监控 Shell Linux
Linux进程控制(详细讲解)
进程等待是系统通过调用特定的接口(如waitwaitpid)来实现的。来进行对子进程状态检测与回收的功能。
75 0
|
3月前
|
存储 负载均衡 算法
Linux2.6内核进程调度队列
本篇文章是Linux进程系列中的最后一篇文章,本来是想放在上一篇文章的结尾的,但是想了想还是单独写一篇文章吧,虽然说这部分内容是比较难的,所有一般来说是简单的提及带过的,但是为了让大家对进程有更深的理解与认识,还是看了一些别人的文章,然后学习了学习,然后对此做了总结,尽可能详细的介绍明白。最后推荐一篇文章Linux的进程优先级 NI 和 PR - 简书。
102 0
|
3月前
|
存储 Linux Shell
Linux进程概念-详细版(二)
在Linux进程概念-详细版(一)中我们解释了什么是进程,以及进程的各种状态,已经对进程有了一定的认识,那么这篇文章将会继续补全上篇文章剩余没有说到的,进程优先级,环境变量,程序地址空间,进程地址空间,以及调度队列。
65 0
|
3月前
|
Linux 调度 C语言
Linux进程概念-详细版(一)
子进程与父进程代码共享,其子进程直接用父进程的代码,其自己本身无代码,所以子进程无法改动代码,平时所说的修改是修改的数据。为什么要创建子进程:为了让其父子进程执行不同的代码块。子进程的数据相对于父进程是会进行写时拷贝(COW)。
67 0
|
7月前
|
编译器 C++ 开发者
【C++篇】深度解析类与对象(下)
在上一篇博客中,我们学习了C++的基础类与对象概念,包括类的定义、对象的使用和构造函数的作用。在这一篇,我们将深入探讨C++类的一些重要特性,如构造函数的高级用法、类型转换、static成员、友元、内部类、匿名对象,以及对象拷贝优化等。这些内容可以帮助你更好地理解和应用面向对象编程的核心理念,提升代码的健壮性、灵活性和可维护性。
|
3月前
|
人工智能 机器人 编译器
c++模板初阶----函数模板与类模板
class 类模板名private://类内成员声明class Apublic:A(T val):a(val){}private:T a;return 0;运行结果:注意:类模板中的成员函数若是放在类外定义时,需要加模板参数列表。return 0;
83 0
|
3月前
|
存储 编译器 程序员
c++的类(附含explicit关键字,友元,内部类)
本文介绍了C++中类的核心概念与用法,涵盖封装、继承、多态三大特性。重点讲解了类的定义(`class`与`struct`)、访问限定符(`private`、`public`、`protected`)、类的作用域及成员函数的声明与定义分离。同时深入探讨了类的大小计算、`this`指针、默认成员函数(构造函数、析构函数、拷贝构造、赋值重载)以及运算符重载等内容。 文章还详细分析了`explicit`关键字的作用、静态成员(变量与函数)、友元(友元函数与友元类)的概念及其使用场景,并简要介绍了内部类的特性。
164 0