C/C++进程超详细详解【下部分】(系统性学习day8)

简介: C/C++进程超详细详解【下部分】(系统性学习day8)

前言

上篇博客对C/C++进程的中部分进行了详细讲解,本篇博客将继续讲解和补充关于线程的知识点。


一,有名管道通信

1 .概念

1.由于无名管道只能用于具有亲缘关系的进程之间,这就限制了无名管道的使用范围。

2.而有名管道可以使互不相关的两个进程互相通信。有名管道可以通过路径名来指出,并且在文件系统中可见

3.进程通过文件IO来操作有名管道

2 .创建有名管道

#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *pathname, mode_t mode);
//参数1 ---- 管道的名称
//参数2 ---- 管道的权限
//返回值 -----成功:0,失败:-1
例如:
int main(int argc ,char **argv)
    {
        if(argc != 2){
            fprintf(stderr,"Usage: %s <fifoname>\n",argv[0]);
            exit(1);
        }
        //创建有名管道
        if(mkfifo(argv[1],0666) < 0){   //管道权限= 0666 & ~umusk
            perror("mkfifo");
            exit(1);
        }
        return 0;
    }

实例代码如下:

//从管道读10个整数,然后排序,并打印
int main(int argc ,char **argv)
{
    int fd;
    int a[10],i,j,flag;
    if(argc != 2){
        fprintf(stderr,"Usage: %s <fifoname>\n",argv[0]);
        exit(1);
    }
 
    //判断管道文件是否存在,如果不存在则创建,存在则直接打开
    if(access(argv[1],F_OK)){
        //创建有名管道
        if(mkfifo(argv[1],0666) < 0){   //管道权限= 0666 & ~umusk
            perror("mkfifo");
            exit(1);
        }
    }
 
    //打开管道
    if((fd = open(argv[1],O_RDWR)) < 0){
        perror("open");
        exit(1);
    }
 
    //从管道中读10个整数
    if(read(fd,a,sizeof(a)) < 0){
        perror("read");
        exit(1);
    }
 
    //排序
    for(i = 0; i < 9; i++){
        flag = 1;
        for(j = 0; j < 9-i; j++)
            if(a[j] > a[j+1]){
                a[j] = a[j] + a[j+1];
                a[j+1] = a[j] - a[j+1];
                a[j] = a[j] - a[j+1];
                flag = 0;
            }
        if(flag)
            break;
    }
    for(i = 0; i < 10; i++){
        printf("%d  ",a[i]);
        fflush(stdout);
        sleep(1);
    }
    printf("\n");
    close(fd);
 
    return 0;
}
//从键盘输入10个整数,并写入管道
int main(int argc ,char **argv)
{
    int fd;
    int a[10],i;
    if(argc != 2){
        fprintf(stderr,"Usage: %s <fifoname>\n",argv[0]);
        exit(1);
    }
 
    //判断管道文件是否存在,如果不存在则创建,存在则直接打开
    if(access(argv[1],F_OK)){
        //创建有名管道
        if(mkfifo(argv[1],0666) < 0){   //管道权限= 0666 & ~umusk
            perror("mkfifo");
            exit(1);
        }
    }
 
    //打开管道
    if((fd = open(argv[1],O_RDWR)) < 0){
        perror("open");
        exit(1);
    }
 
    //键盘输入10个整数
    printf("请输入10个整数:");
    for(i = 0; i < 10; i++){
        scanf("%d",&a[i]);
    }
 
    //向管道中写10个整数
    write(fd,a,sizeof(a));
 
    close(fd);
 
    return 0;
}

二、信号通信

1 .概念

信号是在软件层次上对中断机制的一种模拟,是一种异步通信方式

信号可以直接进行用户空间进程和内核进程之间的交互,内核进程也可以利用它来通知用户空间进程发生了哪些系统事件。

如果该进程当前并未处于执行态,则该信号就由内核保存起来,直到该进程恢复执行再传递给它;如果一个信号被进程设置为阻塞,则该信号的传递被延迟,直到其阻塞被取消时才被传递给进程

2 .用户进程对信号的响应方式

(1)忽略信号:

   对信号不做任何处理,但是有两个信号不能忽略:即SIGKILL及SIGSTOP。

(2)捕捉信号:

   定义信号处理函数,当信号发生时,执行相应的处理函数。

(3)执行缺省操作:

   Linux对每种信号都规定了默认操作

//查看linux系统中的信号---kill

peter@ubuntu:~/2308/proc/day03_code$ kill -l

1) SIGHUP       2) SIGINT       3) SIGQUIT      4) SIGILL       5) SIGTRAP

6) SIGABRT      7) SIGBUS       8) SIGFPE       9) SIGKILL     10) SIGUSR1

11) SIGSEGV     12) SIGUSR2     13) SIGPIPE     14) SIGALRM     15) SIGTERM

16) SIGSTKFLT   17) SIGCHLD     18) SIGCONT     19) SIGSTOP     20) SIGTSTP

21) SIGTTIN     22) SIGTTOU     23) SIGURG      24) SIGXCPU     25) SIGXFSZ

26) SIGVTALRM   27) SIGPROF     28) SIGWINCH    29) SIGIO       30) SIGPWR

31) SIGSYS      34) SIGRTMIN    35) SIGRTMIN+1  36) SIGRTMIN+2  37) SIGRTMIN+3

38) SIGRTMIN+4  39) SIGRTMIN+5  40) SIGRTMIN+6  41) SIGRTMIN+7  42) SIGRTMIN+8

43) SIGRTMIN+9  44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13

48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12

53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9  56) SIGRTMAX-8  57) SIGRTMAX-7

58) SIGRTMAX-6  59) SIGRTMAX-5  60) SIGRTMAX-4  61) SIGRTMAX-3  62) SIGRTMAX-2

63) SIGRTMAX-1  64) SIGRTMAX

3. 用户进程对常用信号的缺省操作

信号名 含义 默认操作
SIGHUP

该信号在用户终端连接(正常或非正常)结束时发出,通常是在终端的控   

制进程结束时,通知同一会话内的各个作业与控制终端不再关联。            

终止
SIGINT 该信号在用户键入INTR字符(通常是Ctrl-C)时发出,终端驱动程序发送                 
此信号并送到前台进程中的每一个进程。                
终止
SIGQUIT 该信号和SIGINT类似,但由QUIT字符(通常是Ctrl-\)来控制。 终止
SIGILL 该信号在一个进程企图执行一条非法指令时(可执行文件本身出现错误,                     
或者试图执行数据段、堆栈溢出时)发出。    
终止
SIGFPE

该信号在发生致命的算术运算错误时发出。这里不仅包括浮点运算错误,                   

 还包括溢出及除数为0等其它所有的算术的错误。    

终止
SIGKILL 该信号用来立即结束程序的运行,并且不能被阻塞、处理和忽略。 终止
SIGALRM 该信号当一个定时器到时的时候发出。 终止
SIGSTOP 该信号用于暂停一个进程,且不能被阻塞、处理或忽略。 暂停进程
SIGTSTP 该信号用于暂停交互进程,用户可键入SUSP字符(通常是Ctrl-Z)发出这个信号。 暂停进程
SIGCHLD 子进程改变状态时,父进程会收到这个信号 忽略
SIGABORT 该信号用于结束进程 终止

4. 信号处理流程

5. 信号相关函数(系统调用)

5.1 kill - 给指定进程发送信号

#include <sys/types.h>
    #include <signal.h>
    int kill(pid_t pid, int sig);
    //参数1  -----信号发送的目标进程的ID
                 参数1取值分四种
                 pid > 0 ,给进程号为pid的进程发送信号
                 pid = 0 , 给当前进程组中每一个进程发送信号
                 pid = -1, 发送给进程表中所有的进程
                 pid < -1, 给指定进程组中的每一个进程发送信号,该进程组的ID为-pid
    //参数2  -----要发送的信号
    //返回值----成功:0,失败:-1
实例代码如下:
int main(int argc,char **argv)
{
#if 1
    pid_t pid;
 
    if(argc != 2){
        fprintf(stderr,"Usage: %s <pid>\n",argv[0]);
        exit(1);
    }
 
    pid = atoi(argv[1]);   //atoi将字符串转为整数
    if(kill(pid,SIGKILL) < 0){
        perror("kill");
        exit(1);
    }
#else
    pid_t pid1,pid2;
    int i;
 
    if((pid1 = fork()) < 0){
        perror("fork");
        exit(1);
    }else if(!pid1){   //子进程1
        for(i = 0; ; i++){
            printf("pid = %d\n",getpid());
            sleep(1);
        }
    }else{
        if((pid2 = fork()) < 0){
            perror("fork");
            exit(1);
        }else if(!pid2){  //子进程2
            for(i = 0; ; i++){
                printf("pid = %d\n",getpid());
                sleep(1);
            }
        }else{  //父进程
            for(i = 0; ; i++){
                printf("pid = %d\n",getpid());
                sleep(1);
                if(i == 5)
                    //kill(0,SIGKILL); //0--给进程组中每一个进程发送信号
                    kill(pid2,SIGKILL);  //给pid2发送信号
            }
        }
    }
 
#endif
    return 0;
}

5.2 raise() --给当前进程发送信号  

#include <signal.h>
int raise(int sig);
//参数 ----信号
//返回值----成功:0,失败:-1
实例代码如下:
int main(void)
{
    int i;
    for(i = 0; ; i++){
        printf("pid = %d\n",getpid());
        sleep(1);
        if(i == 7)
            raise(SIGKILL);
    }
    return 0;
}

5.3 alarm() 在进程中设置定时器(闹钟)  

#include <unistd.h>
unsigned int alarm(unsigned int seconds);
//参数 ---- 要定时的秒数
//返回值 ----如果第一次调用该函数,返回值为0,
            如果调用之前已经设置了定时器,则返回上次定时剩余的秒数
实例代码如下:
int main(void)
{
    int i,ret;
 
    ret = alarm(20);  // 从该语句开始计时,7秒之后发送SIGALRM信号给当前进程
    printf("ret = %d\n",ret);
 
    for(i = 0; ; i++){
        printf("pid = %d,i = %d\n",getpid(),i);
        sleep(1);
        if(i == 7){
            ret = alarm(5);
            printf("ret = %d\n",ret);
        }
    }
    return 0;
}

5.4 pause() 使进程挂起  

int pause(void);

//使进程挂起 ,直到进程收到任意一个信号则返回。

实例代码如下:
//信号处理函数
void fun(int signo)
{
    int i;
    for(i = 0; i < 3; i++){
        printf(GREEN "正在吃饭\n"NONE);
        sleep(1);
    }
}
 
int main(void)
{
    int i,j;
 
    //注册信号SIGALRM
    signal(SIGINT,fun);
 
 
    for(i = 0; ; i++){
        pause();  //使进程挂起,直到收到信号为止
        for(j = 0; j < 5; j++){
            printf("正在睡觉\n");
            sleep(1);
        }
    }
    return 0;
}

5.5 signal 注册信号  

#include <signal.h>
typedef void (*sighandler_t)(int);  //定义函数指针类型名称
sighandler_t signal(int signum, sighandler_t handler);
//参数1 ---- 要注册的信号
//参数2 ---- 信号的响应方式:
                SIG_IGN   ----- 忽略信号
                SIG_DFL   ----- 对信号进行缺省操作
        信号处理函数的指针    ----- 捕捉信号,当收到信号,则会执行信号处理函数
        void xxx_fun(int)
        {
        
        }
//返回值 ----成功:信号处理函数指针,失败:SIG_ERR
实例代码如下:
//信号处理函数
void eat(int signo)
{
    int i;
    for(i = 0; i < 3; i++){
        printf(GREEN "正在吃饭\n"NONE);
        sleep(1);
    }
}
 
int main(void)
{
    int i;
 
    //注册信号SIGALRM
    signal(SIGALRM,eat);
 
 
    for(i = 0; ; i++){
        if(i % 8 == 0){
            alarm(8);  // 从该语句开始计时,7秒之后发送SIGALRM信号给当前进程
            printf("开始睡觉,设置闹钟\n");
        }
        printf("正在睡觉......\n");
        sleep(1);
    }
    return 0;
}


总结

       本篇文章针对进程进行最后的超详细讲解和补充,希望能够帮到大家!

       以后还会给大家展现更多关于嵌入式和C语言的其他重要的基础知识,感谢大家支持懒大王!

相关文章
|
2月前
|
算法 C语言 C++
C++语言学习指南:从新手到高手,一文带你领略系统编程的巅峰技艺!
【8月更文挑战第22天】C++由Bjarne Stroustrup于1985年创立,凭借卓越性能与灵活性,在系统编程、游戏开发等领域占据重要地位。它继承了C语言的高效性,并引入面向对象编程,使代码更模块化易管理。C++支持基本语法如变量声明与控制结构;通过`iostream`库实现输入输出;利用类与对象实现面向对象编程;提供模板增强代码复用性;具备异常处理机制确保程序健壮性;C++11引入现代化特性简化编程;标准模板库(STL)支持高效编程;多线程支持利用多核优势。虽然学习曲线陡峭,但掌握后可开启高性能编程大门。随着新标准如C++20的发展,C++持续演进,提供更多开发可能性。
49 0
|
8天前
|
监控
MASM32写的免费软件“ProcView/系统进程监控” V1.4.4003 说明和下载
MASM32写的免费软件“ProcView/系统进程监控” V1.4.4003 说明和下载
|
11天前
|
C++
【C++案例】一个项目掌握C++基础-通讯录管理系统
这篇文章通过一个通讯录管理系统的C++项目案例,详细介绍了如何使用C++实现添加、显示、删除、查找、修改和清空联系人等功能。
13 3
|
20天前
|
监控 Ubuntu API
Python脚本监控Ubuntu系统进程内存的实现方式
通过这种方法,我们可以很容易地监控Ubuntu系统中进程的内存使用情况,对于性能分析和资源管理具有很大的帮助。这只是 `psutil`库功能的冰山一角,`psutil`还能够提供更多关于系统和进程的详细信息,强烈推荐进一步探索这个强大的库。
29 1
|
28天前
|
安全 开发者 Python
揭秘Python IPC:进程间的秘密对话,让你的系统编程更上一层楼
【9月更文挑战第8天】在系统编程中,进程间通信(IPC)是实现多进程协作的关键技术。IPC机制如管道、队列、共享内存和套接字,使进程能在独立内存空间中共享信息,提升系统并发性和灵活性。Python提供了丰富的IPC工具,如`multiprocessing.Pipe()`和`multiprocessing.Queue()`,简化了进程间通信的实现。本文将从理论到实践,详细介绍各种IPC机制的特点和应用场景,帮助开发者构建高效、可靠的多进程应用。掌握Python IPC,让系统编程更加得心应手。
23 4
|
8天前
|
监控 API
【原创】用Delphi编写系统进程监控程序
【原创】用Delphi编写系统进程监控程序
|
2月前
|
Rust 安全 C++
系统编程的未来之战:Rust能否撼动C++的王座?
【8月更文挑战第31天】Rust与C++:现代系统编程的新选择。C++长期主导系统编程,但内存安全问题频发。Rust以安全性为核心,通过所有权和生命周期概念避免内存泄漏和野指针等问题。Rust在编译时确保内存安全,简化并发编程,其生态系统虽不及C++成熟,但发展迅速,为现代系统编程提供了新选择。未来有望看到更多Rust驱动的系统级应用。
46 1
|
2月前
|
Linux Python
在Linux中,如何查找系统中占用CPU最高的进程?
在Linux中,如何查找系统中占用CPU最高的进程?
|
2月前
|
Linux
在Linux中,如何查看系统上运行的进程?
在Linux中,如何查看系统上运行的进程?
|
2月前
|
存储 算法 数据可视化
【C++】C++旅游管理系统(源码+论文)【独一无二】
【C++】C++旅游管理系统(源码+论文)【独一无二】

相关实验场景

更多
下一篇
无影云桌面