C语言 多进程编程(七)信号量

简介: 本文档详细介绍了进程间通信中的信号量机制。首先解释了资源竞争、临界资源和临界区的概念,并重点阐述了信号量如何解决这些问题。信号量作为一种协调共享资源访问的机制,包括互斥和同步两方面。文档还详细描述了无名信号量的初始化、等待、释放及销毁等操作,并提供了相应的 C 语言示例代码。此外,还介绍了如何创建信号量集合、初始化信号量以及信号量的操作方法。最后,通过实际示例展示了信号量在进程互斥和同步中的应用,包括如何使用信号量避免资源竞争,并实现了父子进程间的同步输出。附带的 `sem.h` 和 `sem.c` 文件提供了信号量操作的具体实现。

进程间通信之信号量

资源竞争

多个进程竞争同一资源时,会发生资源竞争。
资源竞争会导致进程的执行出现不可预测的结果。

临界资源

不允许同时有多个进程访问的资源, 包括硬件资源 (CPU、内存、存储器以及其他外
围设备) 与软件资源(共享代码段、共享数据结构)

临界区

多个进程共享的资源被称为临界资源,
这些资源被保护在一个临界区中,
只有进入临界区的进程才能访问临界资源。

信号量

信号量是一种进程间通信机制,用于协调对共享资源的访问。

多进程对stdout资源的竞争


//多进程对stdout资源的竞争

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

int main(){
   
   

    pid_t cpid;
    cpid = fork();//创建子进程
    if(cpid < 0){
   
   
        printf("fork error\n");//fork失败
        exit(EXIT_FAILURE);//EXIT_FAILURE表示程序运行失败
    } else if(cpid == 0){
   
   //子进程
        while(1){
   
   
            printf("------------------------\n");
            printf("C Start.\n");
            sleep(1);
            printf("C End.\n");
            printf("------------------------\n");
        }
    } else{
   
   //父进程
        while(1){
   
   
            printf("------------------------\n");
            printf("P Start.\n");
            sleep(1);
            printf("P End.\n");
            printf("------------------------\n");
        }

         wait(NULL); //等待子进程结束
    }



    return 0;
}

代码的输出混乱:

------------------------
P Start.
------------------------
C Start.
P End.
------------------------
C End.
------------------------
------------------------
P Start.
------------------------
C Start.
P End.
C End.
------------------------
------------------------

同步和互斥

互斥

互斥是指进程独占资源,使得其他进程无法访问该资源。

同步

同步是指进程间通信,用于协调进程的执行。
同步在互斥的基础上增加了进程对临界资源的访问顺序
进程主要的同步与互斥手段是信号量

信号量

信号量,由内核维护的整数,其值被限制为大于或等于0;
信号可以执行一下操作:

  • 将信号量设置成一个具体的值;
  • 在信号量当前的基础上加上一个数值;
  • 在信号量当前值的基础上减上一个数值;
  • 等待信号量的值为0;

    一般信号量分为

    • 二值信号量:一般指的是信号量值为1,可以理解为只对应一个资源
    • 计数信号量:一般指的是值大于等于2,可以理解为对应多个资源

在linux系统中使用ipcs -s 查询系统中信号量

无名信号量

sem_init()初始化无名信号量

函数头文件:

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>   
#include <semaphore.h>
int sem_init(sem_t *sem, int pshared, unsigned int value);

函数功能:初始化一个无名信号量;

函数参数:
- sem: 指向信号量的指针;
- pshared: 共享标志位, 
      - 0表示不共享, 两个线程间同步
      - 非0表示共享,两个进程间同步;

- value: 信号量的初始值;
       -  如果是1表示可以获取信号量
       - 如果是0表示不可以获取信号量

函数返回值:
- 成功: 返回0;
- 失败: 返回-1, 并设置errno;



### sem_wait()等待信号量

函数头文件:

```c
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>   
#include <semaphore.h>
int sem_wait(sem_t *sem);

函数功能:等待信号量;

函数参数:

  • sem: 指向信号量的指针;(将信号量的值-1)
  • 如果信号量的值已经是0了,则sem_wait会阻塞,等到能执行减1操作为止

函数返回值:

  • 成功: 返回0;
  • 失败: 返回-1, 并设置errno;

sem_post()释放信号量

函数头文件:

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>   
#include <semaphore.h>
int sem_post(sem_t *sem);

函数功能:

释放信号量;(将信号量的值+1)

函数参数:

  • sem: 指向信号量的指针;

函数返回值:

  • 成功: 返回0;
  • 失败: 返回-1, 并设置errno;

sem_destroy()销毁信号量

函数头文件:

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>   
#include <semaphore.h>  
int sem_destroy(sem_t *sem);

函数功能:销毁信号量;

函数参数:

  • sem: 指向信号量的指针;

函数返回值:

  • 成功: 返回0;
  • 失败: 返回-1, 并设置errno;
  • 如果信号量已经被销毁,则再次调用 sem_destroy() 不会有任何作用, 不会报错;

创建信号量集合

调用 semget() 函数

函数头文件:

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


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

函数功能:创建一个信号量集合;

函数参数:

  • key: 信号量集合的键值, 用于标识信号量集合;由ftok()函数生成;
  • nsems: 信号量集合中信号量的个数;
  • semflg: 信号量集合的标志位, 用于设置信号量集合的属性;
    • IPC_CREAT: 如果key对应的信号量集合不存在, 则创建新的信号量集合;
    • IPC_EXCL: 如果key对应的信号量集合已经存在, 则返回-1;
    • 权限标志

函数返回值:

  • 成功: 返回信号量集合的ID;
  • 失败: 返回-1, 并设置errno;
//多进程对stdout资源的竞争

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

#define MSG_PATH "/home/gopher"
#define MSG_ID 88
int main(){
   
   
    key_t key;
    //通过文件路径和ID生成key,
    key= ftok(MSG_PATH,MSG_ID);
    if(key==-1){
   
   
        printf("ftok()");
        exit(EXIT_FAILURE);
    }

    //创建信号量集合,包含了一个信号量,编号为0
    int semid=semget(key,1,IPC_CREAT|0666);
    if(semid==-1){
   
   
        printf("semget()");
        exit(EXIT_FAILURE);
    }

    return 0;
}

创建出一个信号量集合,包含了一个信号量,编号为0

img_47.png

初始化信号量

调用 semctl() 函数

函数头文件:

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


int semctl(int semid, int semnum, int cmd, ... /* arg */ );

函数功能:对信号量集合中的信号量进行操作;根据cmd 决定当前函数的功能;

函数参数:

  • semid: 信号量集合的ID;
  • semnum: 信号量的编号;编号从0开始;
  • cmd: 信号量操作命令;
    • SETVAL:设置信号量的值。
    • GETPID:返回最后一个执行 semop 操作的进程的PID。
    • GETVAL:返回指定信号量的值。不需要第四个参数
    • GETALL:返回信号量集中所有信号量的值。
    • GETNCNT:返回正在等待信号量增加的进程数。
    • GETZCNT:返回正在等待信号量变为零的进程数。
    • SETALL:设置信号量集中所有信号量的值。
    • IPC_STAT:获取信号量集的状态信息。 第二参数被忽略,第四个参数buf选项
    • IPC_SET:设置信号量集的状态信息。第二参数被忽略,第四个参数buf选项
    • IPC_RMID:删除信号量集。
  • ... :是属于可变参参数列表,根据不同的命令有不同的参数;

函数返回值:

  • 成功: 根据不同的cmd, 返回不同的结果;
  • GETPID:返回等待最后一个 semop 操作的进程的 PID。

    GETVAL:返回指定信号量的值。
    ls
    GETALL:如果成功,返回 0。

    GETNCNT:返回正在等待增加信号量值的进程数量。

    GETZCNT:返回正在等待信号量值为零的进程数量。

    IPC_STAT:如果成功,返回 0。

    IPC_SET:如果成功,返回 0。

    IPC_RMID:如果成功,返回 0。

    SETVAL:如果成功,返回 0。

    SETALL:如果成功,返回 0。

  • 失败: 返回-1, 并设置errno;

//多进程对stdout资源的竞争

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

#define MSG_PATH "/home/gopher"
#define MSG_ID 88

union semun{
   
   
    int val;
};
int main(){
   
   
    key_t key;
    //通过文件路径和ID生成key,
    key= ftok(MSG_PATH,MSG_ID);
    if(key==-1){
   
   
        printf("ftok()");
        exit(EXIT_FAILURE);
    }

    //创建信号量集合,包含了一个信号量,编号为0
    int semid=semget(key,1,IPC_CREAT|0666);
    if(semid==-1){
   
   
        printf("semget()");
        exit(EXIT_FAILURE);
    }

      union semun s;//定义一个联合体,用于设置信号量的值
      s.val=1;//设置信号量的值为1
      int ret=semctl(semid,0,SETVAL,s);//设置semid信号集中的第编号为0的信号量的值为1
      if(ret==-1){
   
   
          printf("semctl()");
          exit(EXIT_FAILURE);
      }

    return 0;
}

信号量操作

  • 信号量可以进⾏以下操作:
    • 对信号量的值加 1
    • 对信号量的值减 1
    • 等待信号量的值为 0

调用 semop() 函数

函数头文件:

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


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

函数功能:对信号量集合中的信号量进行操作;

函数参数:

  • semid: 信号量集合的ID;
  • sops: 信号量操作结构体指针
  • nsops: 信号量操作结构体的个数;

函数返回值:

  • 成功: 返回 0;
  • 失败: 返回-1, 并设置errno;

struct sembuf *sops: 信号量操作结构体指针
```c
struct sembuf
{
unsigned short int sem_num;//信号量编号,从0开始
short int sem_op; //信号量操作
//-1:占用资源
// +1:释放资源
// 0:等待资源

short int sem_flg; //信号量操作标志位
//IPC_NOWAIT:非阻塞,在信号量的值为0时,立即返回
// SEM_UNDO:在进程终止时,会自动释放信号量
};


## 信号量集合删除

调用 semctl() 函数 ,设置命令为 IPC_RMID

在使用 semctl() 函数删除信号量集合时,需要注意第三个参数会被忽略

## 信号量互斥应用

> 使用信号量实现进程间互斥,同一时间只有一个进程访问临界资源
> 
> 
1.创建sem.h

```c

#ifndef _mySEM_H_
#define _mySEM_H_
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>

//创建信号量集
int sem_create(int names,unsigned short value[]);
//占用信号量
int sem_p(int semid,int semnum);
//释放信号量
int sem_v(int semid,int semnum);
//删除信号量集
int sem_delete(int semid);


#endif /* _SEM_H_ */

2.创建sem.c


#include "sem.h"

union semun {
   
   
               int              val;    val 是一个整数类型,用于 SETVAL 命令,该命令用于设置信号量的值。
               struct semid_ds *buf;    一个指向 struct semid_ds 结构的指针。semid_ds 结构用于存储信号量集合的状态信息。
                                          buf 用于 IPC_STAT 和 IPC_SET 命令,分别用于获取和设置信号量集合的状态信息。
               unsigned short  *array;  一个指向无符号短整数数组的指针。
                                      该数组用于 GETALL 和 SETALL 命令,分别用于获取和设置信号量集合中所有信号量的值
               struct seminfo  *__buf;  一个指向 struct seminfo 结构的指针。seminfo 结构用于存储信号量集合的详细信息。
                                      __buf 用于 IPC_INFO 命令,该命令用于获取信号量集合的详细信息。这个成员是 Linux 特定的。
           };


//创建信号量集
//@param names 信号量集的个数
//@param value 信号量集的初始值
//@return 成功返回信号量集的id,失败返回-1
int sem_create(int names,unsigned short value[]){
   
   
    key_t key;
    //创建key
    key= ftok(".",88);
    if (key == -1){
   
   
        perror("ftok");
        return -1;
    }

    //创建信号量集
    int semid;
    semid = semget(key,names,IPC_CREAT|0666);//参数:key,信号量集的个数,权限
    if (semid == -1)
    {
   
   
        perror("semget");
        return -1;
    }


    union semun s; //定义union semun
    s.array = value;//将value数组赋值给union semun的array成员
    //初始化信号量集
    int ret=semctl(semid,0,SETALL,s);//这个操作将value数组中的值设置到信号量集中
    if (ret == -1){
   
   
        perror("semctl");
        return -1;
    }

    return semid;


}



//占用信号量
//@param semid 信号量集的id
//@param semnum 信号量的编号
int sem_p(int semid,int semnum){
   
   
    struct sembuf sem_b;//定义一个信号量操作结构体
    sem_b.sem_num=semnum;//信号量编号
    sem_b.sem_op= -1;//占用资源
    sem_b.sem_flg=SEM_UNDO;//在进程终止时,会自动释放信号量
    //操作1个信号量,如果操作多个信号量,需要创建sembuf结构体的数组
    int r= semop(semid,&sem_b,1); //失败返回-1,并设置errno   
    return r;
}
//释放信号量
int sem_v(int semid,int semnum){
   
   
 struct sembuf sem_b;//定义一个信号量操作结构体
    sem_b.sem_num=semnum;//信号量编号
    sem_b.sem_op= 1;//释放资源
    sem_b.sem_flg=SEM_UNDO;//在进程终止时,会自动释放信号量,

    int r= semop(semid,&sem_b,1); //操作1个信号量,如果操作多个信号量,需要创建sembuf结构体的数组
    //失败返回-1,并设置errno   
    return r;
}
//删除信号量集
int sem_delete(int semid){
   
   
    int r= semctl(semid,0,IPC_RMID); //删除信号量集
    return r;
}

3.创建main.c


// 多进程对stdout资源的竞争

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
#include "sem.h"
int main()
{
   
   

    int semid;// 信号量ID
    unsigned short values[] = {
   
   1};// 信号量初始值

    semid = sem_create(1, values);
    if(semid == -1 ){
   
   
        printf("sem_create error\n");
        exit(EXIT_FAILURE);
    }




    pid_t cpid;// 子进程ID

    cpid = fork(); // 创建子进程
    if (cpid < 0)
    {
   
   
        printf("fork error\n"); // fork失败
        exit(EXIT_FAILURE);     // EXIT_FAILURE表示程序运行失败
    }
    else if (cpid == 0)
    {
   
    // 子进程
        while (1)
        {
   
   
            sem_p(semid,0);
            printf("------------------------\n");
            printf("C Start.\n");
            sleep(1);
            printf("C End.\n");
            printf("------------------------\n");
            sem_v(semid,0);

        }
    }
    else
    {
   
    // 父进程
        while (1)
        {
   
   
            sem_p(semid,0);
            printf("------------------------\n");
            printf("P Start.\n");
            sleep(1);
            printf("P End.\n");
            printf("------------------------\n");
            sem_v(semid,0);
        }

        wait(NULL); // 等待子进程结束
    }

    return 0;
}

4.编译运行



------------------------
P Start.
P End.
------------------------
------------------------
C Start.
C End.
------------------------
------------------------
P Start.
P End.
------------------------
------------------------
C Start.
C End.
----------

信号量同步应用

同步在互斥的基础上增加了进程对临界资源的访问顺序
进程主要的同步与互斥手段是信号量

示例:

创建⽗⼦进程,输出 “ABA” 字符串,具体需求如下:
⽗进程 输出 A
⼦进程 输出 B
⽗进程 输出 A ,输出换⾏
能够循环输出 “ABA” 字符

基本思路:

通过创建⼀个信号量集合,包含 2 个信号量,⼀个信号量 编号为 0
(SEM_CONTROL_P)控制⽗进程的运⾏与暂停,⼀个信号量 编号为 1
(SEM_CONTROL_C) 控制⼦进程的运⾏与暂停

// 多进程对stdout资源的竞争

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

#define SEM_C = 1
#define SEM_P = 0
// todo 创建一个信号量集合,集合中两个信号量,信号量0的值是1,信号量1的值是0;
int main()
{
   
   

    int semid;                         // 信号量ID
    unsigned short values[2] = {
   
   1, 0}; // 信号量初始值
    // todo 创建一个信号量集合,集合中两个信号量,信号量编号0的值是1,信号量编号1的值是0;
    semid = sem_create(2, values);
    if (semid == -1)
    {
   
   
        printf("sem_create error\n");
        exit(EXIT_FAILURE);
    }

    pid_t cpid; // 子进程ID

    cpid = fork(); // 创建子进程
    if (cpid < 0)
    {
   
   
        printf("fork error\n"); // fork失败
        exit(EXIT_FAILURE);     // EXIT_FAILURE表示程序运行失败
    }
    else if (cpid == 0)
    {
   
    // 子进程
        while (1)
        {
   
   
            sem_p(semid, 1); //?占用信号量编号1,信号量编号1的值初始是0 ,在这里阻塞,等待父进程操作
            printf("B");
            fflush(stdout); // 刷新缓冲
            sem_v(semid, 0); //!释放信号量编号0,信号量编号0的值 0=>1,此时父进程不再阻塞,第二次占用0

        }
    }
    else
    {
   
    // 父进程
        while (1)
        {
   
   
            //@param semid 信号量集的id
            //@param semnum 信号量的编号
            sem_p(semid, 0); //?占用信号量编号0,信号量编号0的值 1=>0
            printf("A");
            fflush(stdout);  // 刷新缓冲
            sem_v(semid, 1); //?释放信号量编号1,信号量编号1的值 0=>1,此时子进程不再阻塞
            sem_p(semid, 0); //!第二次占用信号量编号0,信号量编号0的值是0,在这里阻塞,等待子进程的操作
            printf("A\n");
            fflush(stdout);  // 刷新缓冲
            sem_v(semid, 0);
            sleep(1);

        }

        wait(NULL); // 等待子进程结束
    }

    return 0;
}

+

sem.h:

#ifndef __SEM_H__
#define __SEM_H__
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/ipc.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <errno.h>

#define SHM_PATH "/home/gopher"
#define SHM_ID 1234
//初始化信号量
int sem_init(int num);
//信号量P操作
int sem_p(int semid, int num);
//信号量V操作
int sem_v(int semid, int num);
//销毁信号量
int sem_destroy(int semid);

#endif

sem.c:


#include "sem.h"
//初始化信号量
//@param num 信号量的数量
int sem_init(int num){
   
   
    key_t key;//消息队列的key
    //通过文件路径和ID生成key,
    key= ftok(SHM_PATH,SHM_ID);
    if(key==-1){
   
   
        printf("ftok() error\n");
        exit(EXIT_FAILURE);
    }
    printf("key: %d\n",key);

    //创建共享内存
    //@param key 共享内存的key
    //@param nsems 共享内存的数量
    //@param semflg 共享内存的标志
    int semid = semget(key,2,IPC_CREAT|0666);
    if(semid==-1){
   
   
        if (errno== EEXIST ){
   
   //EEXIST文件存在
                printf("信号量集合已存在\n");//提示已存在
              if(-1==(semid = semget(key,2,IPC_CREAT|0666))){
   
   
                  return semid;
              }
        }
        printf("semget()");
        exit(EXIT_FAILURE);
    }

    //初始化信号量
    for(int i = 0; i < num; i++){
   
   
        //设置信号量的值
        if(-1 == semctl(semid, i, SETVAL, !i)){
   
   
            printf("semctl() error\n");
            exit(EXIT_FAILURE);
        }
    }
    return semid;
}
//信号量P操作
int sem_p(int semid, int num){
   
   
    struct sembuf s={
   
   
            .sem_num=num,//信号量的编号
           .sem_op=-1,//P操作
           .sem_flg=0 //操作标志
    };
    //P操作
    //@param semid 信号量集合ID
    //@param s 信号量操作结构体
    //@param nsops 信号量操作结构体的数量
    semop(semid,&s,1);
    return 0;
}
//信号量V操作
int sem_v(int semid, int num){
   
   
    struct sembuf s={
   
   
            .sem_num=num,//信号量的编号
            .sem_op=1,//V操作
            .sem_flg=0//操作标志
    };
    //V操作
    //@param semid 信号量集合ID
    //@param s 信号量操作结构体
    //@param nsops 信号量操作结构体的数量
    semop(semid,&s,1);
    return 0;
}
//销毁信号量
int sem_destroy(int semid){
   
   
    //销毁信号量集合
    //@param semid 信号量集合ID
    //@param semnum 信号量的数量
    //@param semflg 信号量的操作标志//删除信号灯集 第二参数被忽略,第4个参数不用填写
    semctl(semid,0,IPC_RMID);

    return 0;
}
相关文章
|
8天前
|
安全 开发者 Python
揭秘Python IPC:进程间的秘密对话,让你的系统编程更上一层楼
【9月更文挑战第8天】在系统编程中,进程间通信(IPC)是实现多进程协作的关键技术。IPC机制如管道、队列、共享内存和套接字,使进程能在独立内存空间中共享信息,提升系统并发性和灵活性。Python提供了丰富的IPC工具,如`multiprocessing.Pipe()`和`multiprocessing.Queue()`,简化了进程间通信的实现。本文将从理论到实践,详细介绍各种IPC机制的特点和应用场景,帮助开发者构建高效、可靠的多进程应用。掌握Python IPC,让系统编程更加得心应手。
12 4
|
12天前
|
网络协议 C语言
C语言 网络编程(十三)并发的TCP服务端-以进程完成功能
这段代码实现了一个基于TCP协议的多进程并发服务端和客户端程序。服务端通过创建子进程来处理多个客户端连接,解决了粘包问题,并支持不定长数据传输。客户端则循环发送数据并接收服务端回传的信息,同样处理了粘包问题。程序通过自定义的数据长度前缀确保了数据的完整性和准确性。
|
12天前
|
Linux C语言
C语言 多进程编程(四)定时器信号和子进程退出信号
本文详细介绍了Linux系统中的定时器信号及其相关函数。首先,文章解释了`SIGALRM`信号的作用及应用场景,包括计时器、超时重试和定时任务等。接着介绍了`alarm()`函数,展示了如何设置定时器以及其局限性。随后探讨了`setitimer()`函数,比较了它与`alarm()`的不同之处,包括定时器类型、精度和支持的定时器数量等方面。最后,文章讲解了子进程退出时如何利用`SIGCHLD`信号,提供了示例代码展示如何处理子进程退出信号,避免僵尸进程问题。
|
12天前
|
C语言
C语言 网络编程(八)并发的UDP服务端 以进程完成功能
这段代码展示了如何使用多进程处理 UDP 客户端和服务端通信。客户端通过发送登录请求与服务端建立连接,并与服务端新建的子进程进行数据交换。服务端则负责接收请求,验证登录信息,并创建子进程处理客户端的具体请求。子进程会创建一个新的套接字与客户端通信,实现数据收发功能。此方案有效利用了多进程的优势,提高了系统的并发处理能力。
|
12天前
|
消息中间件 Unix Linux
C语言 多进程编程(五)消息队列
本文介绍了Linux系统中多进程通信之消息队列的使用方法。首先通过`ftok()`函数生成消息队列的唯一ID,然后使用`msgget()`创建消息队列,并通过`msgctl()`进行操作,如删除队列。接着,通过`msgsnd()`函数发送消息到消息队列,使用`msgrcv()`函数从队列中接收消息。文章提供了详细的函数原型、参数说明及示例代码,帮助读者理解和应用消息队列进行进程间通信。
|
12天前
|
缓存 Linux C语言
C语言 多进程编程(六)共享内存
本文介绍了Linux系统下的多进程通信机制——共享内存的使用方法。首先详细讲解了如何通过`shmget()`函数创建共享内存,并提供了示例代码。接着介绍了如何利用`shmctl()`函数删除共享内存。随后,文章解释了共享内存映射的概念及其实现方法,包括使用`shmat()`函数进行映射以及使用`shmdt()`函数解除映射,并给出了相应的示例代码。最后,展示了如何在共享内存中读写数据的具体操作流程。
|
4天前
|
存储 Serverless C语言
【C语言基础考研向】11 gets函数与puts函数及str系列字符串操作函数
本文介绍了C语言中的`gets`和`puts`函数,`gets`用于从标准输入读取字符串直至换行符,并自动添加字符串结束标志`\0`。`puts`则用于向标准输出打印字符串并自动换行。此外,文章还详细讲解了`str`系列字符串操作函数,包括统计字符串长度的`strlen`、复制字符串的`strcpy`、比较字符串的`strcmp`以及拼接字符串的`strcat`。通过示例代码展示了这些函数的具体应用及注意事项。
|
7天前
|
存储 C语言
C语言程序设计核心详解 第十章:位运算和c语言文件操作详解_文件操作函数
本文详细介绍了C语言中的位运算和文件操作。位运算包括按位与、或、异或、取反、左移和右移等六种运算符及其复合赋值运算符,每种运算符的功能和应用场景都有具体说明。文件操作部分则涵盖了文件的概念、分类、文件类型指针、文件的打开与关闭、读写操作及当前读写位置的调整等内容,提供了丰富的示例帮助理解。通过对本文的学习,读者可以全面掌握C语言中的位运算和文件处理技术。
|
7天前
|
存储 C语言
C语言程序设计核心详解 第七章 函数和预编译命令
本章介绍C语言中的函数定义与使用,以及预编译命令。主要内容包括函数的定义格式、调用方式和示例分析。C程序结构分为`main()`单框架或多子函数框架。函数不能嵌套定义但可互相调用。变量具有类型、作用范围和存储类别三种属性,其中作用范围分为局部和全局。预编译命令包括文件包含和宏定义,宏定义分为无参和带参两种形式。此外,还介绍了变量的存储类别及其特点。通过实例详细解析了函数调用过程及宏定义的应用。
|
12天前
|
Linux C语言
C语言 多进程编程(三)信号处理方式和自定义处理函数
本文详细介绍了Linux系统中进程间通信的关键机制——信号。首先解释了信号作为一种异步通知机制的特点及其主要来源,接着列举了常见的信号类型及其定义。文章进一步探讨了信号的处理流程和Linux中处理信号的方式,包括忽略信号、捕捉信号以及执行默认操作。此外,通过具体示例演示了如何创建子进程并通过信号进行控制。最后,讲解了如何通过`signal`函数自定义信号处理函数,并提供了完整的示例代码,展示了父子进程之间通过信号进行通信的过程。

相关实验场景

更多