精华内容
下载资源
问答
  • Linux是免费开源的操作系统,随着时代的发展...Linux系统软件不仅包含完整的Linux操作系统,还包含了文本编辑器、高级语言编译器、以及X-Windows图形用户界面等应用软件,当我们使用Linux的时候可以像使用Windows7、Win

    Linux是免费开源的操作系统,随着时代的发展以及进步,越来越多的企业都开始使用Linux。那么Linux有什么特点,为何如此受欢迎呢?下面和千锋广州小编一起来看看吧!

    Linux系统以高效和灵活著称,Linux运行在PC上,是在GNU 通用公共许可(GPL)权限下免费获得的,是一个符合POSIX 标准的操作系统。

    Linux系统软件不仅包含完整的Linux操作系统,还包含了文本编辑器、高级语言编译器、以及X-Windows图形用户界面等应用软件,当我们使用Linux的时候可以像使用Windows7、Windows8一样,通过窗口、图标和菜单对系统进行操作,这是Linux个人桌面领域的应用,在服务器领域绝大多数场景下都是使用命令行、文本模式操作Linux。

    Linux系统之所以受到计算机爱好者喜欢,有两大原因:

    第一,Linux属于自由软件,用户不用支付任何费用就可以获得系统和系统源代码,并且可以根据自己的需要对源代码进行必要的修改,无偿使用,无约束的自由传播。

    第二,Linux具有Unix的全部优秀特性,任何使用Unix操作系统或者想要Unix操作系统的人,都可以通过学习Linux了解Unix,可以获得Unix中几乎所有优秀功能,并且更加开放,社区开发和其他使用也是非常活跃的。

    不仅这样,Linux还有很多特点,Linux是Unix在PC上的克隆版,仿Unix内核构建,几乎与Unix指令集向下完全兼容;同时是一个完善的支持多用户、多任务、多进程、多CPU的系统;具有很高的系统稳定性与可靠性、很高的系统安全性;有完善的网络服务。

    展开全文
  • 问1:什么是程序,什么是进程,有什么区别?...问2:如何查看系统有哪些进程? 使用ps指令查看,实际工作中,配合grep来查找程序中是否存在某一进程 grep 3标题 3标题 3标题 ...

    进程相关概念

    问1:什么是程序,什么是进程,有什么区别?

    1. 程序是静态的概念,gcc xxx.c -o pro,磁盘中生成pro文件,叫做程序
    2. 进程是程序的一次运行活动,通俗点意思是程序跑起来了,系统中就多了一个进程

    问2:如何查看系统中有哪些进程?

    1. 使用ps指令查看,实际工作中,配合grep来查找程序中是否存在某一进程
    2. grep类似于管道,可以筛选自己需要的
    ps -aux|grep xxx//你生成可执行文件的名字,gcc直接编译的话,就是a.out
    

    什么是进程标识符?

    1. 每个进程都有一个非负整数表示的唯一ID,叫做pid,类似身份证。
    2. Pid = 0:称为交换进程(swapper)作用——进程调度(通俗讲就是谁先跑)
    3. Pid = 1 : init进程,作用——系统初始化
    4. top类似Windows的任务管理器
    5. getppid可以调用父进程
      例子:
    #include <stdio.h>
    #include <sys/types.h>
    #include <unistd.h>
    
    int  main()
    {
        pid_t pid;
        pid = getpid();
        printf("this is mypid: %d\n", pid);
        while(1);
        return 0;
    }
    

    可以使用

    man 2 getpid
    

    来查询需要的头文件

    什么叫父进程.什么叫子进程?

    进程A创建了进程B,那么A叫做父进程,B叫做子进程,父子进程是相对的概念,理解为人类的父子关系

    C程序的存储空间是如何分配?(面试题常考)

    • 正文段。这是由CPU执行的机器指令部分。通常,正文段是可共享的,所以即使是频繁执行的程序(如文本编辑器、C编辑器和shell等)在存储器中也只需有一个副本,另外,正文段常常是只读,以防止程序由于意外而修改其自身的指令。

    • 初始化数据段。通常将此段称为数据段,它包含了程序中需明确地赋初值的变量。例如,C程序中出现在任何函数之外的声明:
      int maxcount = 99;

    • 非初始化数据段。通常将此段称为bss,这一名称来源于一个早期的汇编运算符,意思是“black started by symbol”(由符号开始的块),在程序开始执行之前,内核将此段中的数据初始化为0或空指针。出现在任何函数外的C声明
      long sum[1000];
      使此变量存放在非初始化数据段中。

    • 栈。自动变量以及每次函数调用时所需保存的信息都存放在此段中。每次调用函数时,其返回地址以及调用者的环境信息(例如某些机器寄存器的值)都放在栈中。然后,最近被调用的函数在栈上为其自动和临时变量分配存储空间。通过以这种方式使用栈,可以递归调用C函数。递归函数每次调用自身时,就使用一个新的栈帧,因此一个函数调用实例中的变量集不会影响另一个函数调用实例中的变量。

    • 堆。通常在堆中进行动态存储分配。由于历史上形成的惯例,堆位于非初始化数据段和栈之间。

    创建进程函数fork的使用(进程创建实战)

    1. 使用
    fork_t fork(void);
    

    fork函数调用成功,返回两次
    返回值为0,代表当前进程是子进程
    返回值为非负数,代表当前进程为父进程
    调用失败,返回-1

    例子:

                                                                        
       #include <stdio.h>
       #include <unistd.h>
       
       int main()
       
       {
           pid_t pid;
           pid = fork();
         if(pid > 0)
        {
            printf("this is father, pid=%d\n", getpid());
         }
        else if(pid == 0)
        {
           printf("this is child, pid=%d\n", getpid());
        }
         return 0;
      }
    

    结果:

    this is father, pid=4609
    this is child, pid=4610
    

    创建进程函数fork的使用补充

    返回值到底是啥?

    #include <stdio.h>
    #include <unistd.h>
    
    int main()
    
    {
        pid_t pid;
        pid_t retpid;
        pid_t pid2;
    
        pid = getpid();
        printf("before fork: pid = %d\n", pid);
        retpid = fork();
        pid2 = getpid();
        printf("after fork: pid = %d\n", pid2);
    
    
    
        if(pid == pid2)
        {
            printf("this is father, pid=%d, retpid=%d\n", getpid(), retpid);
        }
        else
        {
            printf("this is child, pid=%d, retpid=%d\n", getpid(), retpid);
        }
        return 0;
    }
    

    结果:

    before fork: pid = 4706
    after fork: pid = 4706
    this is father, pid=4706, retpid=4707
    after fork: pid = 4707
    this is child, pid=4707, retpid=0
    
    

    进程创建发生了什么事

    什么是写实拷贝(面试题)
    write on copy
    linux内核在创建新的进程时,使用该技术,只有当子进程数据发生改变后,才会将父进程的内容复制一份给子进程。

    例子:

    #include <stdio.h>
    #include <unistd.h>
    
    int main() {
        pid_t pid;
        pid = fork();
        int data = 10;
        if (pid > 0) {
            printf("this is father, pid=%d\n", getpid());
    
        } else if (pid == 0) {
            printf("this is child, pid=%d\n", getpid());
    
            data = data + 100;
        }
        printf("data= %d\n", data);
        return 0;
    }
    

    结果:

    this is father, pid=5004
    data= 10
    this is child, pid=5005
    data= 110
    
    

    创建新进程的实际应用场景及fork总结

    fork创建一个子进程的一般目的

    1. 一个父进程希望复制自己,使父、子进程同事执行不同的代码段。这在网络服务进程中是常见的——父进程等待客户端的服务请求。当这种请求到达时,父进程调用fork,使子进程处理此请求。父进程则继续等待下一个服务请求到达。
    2. 一个进程要执行一个不同的程序。这对shell是常见的情况。在这种情况下,子进程从fork返回后立即调用exec(我们将在8.10节说明exec)。
      ps:
      文字摘自《Unix环境高级编程》

    fork编程实战

    一个现有进程可以调用fork函数创建一个新进程。

    #include <unistd.h>
    pid_t fork(void);
    

    返回值:子进程中返回0,父进程中返回子进程ID.出错返回-1

    由fork创建的新进程被称为子进程(child process)。fork函数被调用一次,但返回两次。
    两次返回的唯一区别是子进程的返回值是0,而父进程的返回值则是新子进程的进程ID。

    将子进程ID返回给父进程的理由是:因为一个进程的子进程可以有多个,并且没有一个函数使一个进程可以获得其所有子进程的进程ID。

    fork使子进程得到返回值0的理由是:一个进程只会有一个父进程,所以子进程总是可以调用getppid以获得其父进程的进程ID(进程ID 0总是由内核交换进程使用,所以一个子进程的进程ID不可能为0)。

    子进程和父进程继续执行fork调用之后的指令。子进程是父进程的副本。例如,子进程获得父进程数据空间、堆和栈的副本。注意,这是子进程所拥有的副本。父、子进程并不共享这些存储空间部分。父、子进程共享正文段(见7.6节)。

    由于在fork之后经常跟随着exec,所以现在的很多实现并不执行一个父进程数据段、栈和堆的完全复制、作为 替代,使用了写时复制(Copy-On-Write,COW)技术。这些区域由父、子进程共享,而且内核将它们的权限改变为只读。如果父、子进程中的任一个试图修改这些区域,则内核只为修改区域的那块内存制作一个副本,通常是虚拟存储器系统中的一“页”。
    例子:
    模拟QQ服务端和客户端,只有当满足条件时才会创建一个子进程

    #include <stdio.h>
    #include <unistd.h>
    
    
    int main()
    {
        pid_t pid;
        int data = 10;
        while(1)
        {
            printf("please input a data\n");
            scanf("%d", &data);
            if(data == 1)
            {
                pid = fork();
                if(pid > 0)
                {}
                else if(pid == 0)
                {
                    while(1)
                    {
                        printf("do net request, pid = %d\n", getpid());
                        printf("data= %d\n",data);
                        sleep(3);
                    }
                }
            }
            else{
            
                printf("wait, do nothing\n");
            }
        }
        return 0;
    }
    

    vfork创建进程

    vfork函数也可以创建进程,与fork有什么区别
    关键区别一:
    vfork直接使用父进程存储空间,不拷贝。
    关键区别二:
    vfork保证子进程先运行,当子进程调用exit退出后,父进程才执行。

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    
    int main() {
        pid_t pid;
        int cnt = 0;
        pid = vfork();
        if (pid > 0) {
            while (1) {
                printf("this is father, pid=%d\n", getpid());
                sleep(1);
                printf("cnt=%d\n", cnt);
            }
        } else if (pid == 0) {
            while (1) {
                printf("this is child, pid=%d, cnt=%d\n", getpid(), cnt);
                    cnt++;
                if (cnt == 3) {
                    exit(0);
                }
            }
        }
        return 0;
    }
    
    

    进程退出

    正常退出(5)

    1. Main函数调用return
    2. 进程调度exit(),标准C库
    3. 进程调度_exit()或者_Exit(),属于系统调用
    4. 进程最后一个线程返回
    5. 最后一个线程调用pthread_exit

    异常退出(3)

    1. 调用abort
    2. 当进程收到某些信号时,如ctrl+C
    3. 最后一个线程对取消(cancellation)请求做出响应。

    不管进程如何终止,最后都会执行内核中的同一段代码。这段代码为相应进程关闭所有打开描述符,释放它所使用的存储器等。
    对上述任意一种终止情形,我们都希望终止进程能够通知其父进程它是如何终止的。对于三个终止函数(exit、_exit和_Exit),实现这一点的方法是,将其退出状态(exit status)作为参数传送给函数。在异常终止情况下,内核(不是进程本身)产生一个指示其异常终止原因的终止状态(termination status)。在任意一种情况下,该终止进程的父进程都能用wait或waitpid函数(在下一节说明)取得其终止状态。
    (exit会对缓冲区进行冲刷,对一些变量做处理,但是剩下两个是直接退出,一般使用exit)

    父进程等待子进程退出(一)(wait)

    为什么要收集子进程?

    子进程退出状态不被收集,变成僵死进程(僵尸进程)

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    
    int main() {
        pid_t pid;
        int cnt = 0;
        pid = fork();
        if (pid > 0) {
            while (1) {
                printf("cnt=%d\n", cnt);
                printf("this is father, pid=%d\n", getpid());
                sleep(1);
            }
        } else if (pid == 0) {
            while (1) {
                printf("this is child, pid=%d, cnt=%d\n", getpid(), cnt);
                sleep(1);
                cnt++;
                if (cnt == 5) {
                exit(0);
                }
            }
        }
        return 0;
    }
    
    

    运行代码使用:

    ps -aux|grep xxx
    

    得到结果:

    Warning: bad ps syntax, perhaps a bogus '-'? See http://procps.sf.net/faq.html
    book      7188  0.1  0.0   4172   352 pts/3    S+   18:23   0:00 ./a.out
    book      7189  0.0  0.0      0     0 pts/3    Z+   18:23   0:00 [a.out] <defunct>
    book      7191  0.0  0.0  13600   936 pts/6    S+   18:23   0:00 grep --color=auto a.out
    
    

    这里的z+是zombie(僵尸)
    s+是正在进行

    解决方案:

    NAME
           wait, waitpid, waitid - wait for process to change state
    
    SYNOPSIS
           #include <sys/types.h>
           #include <sys/wait.h>
    
           pid_t wait(int *status);
    
           pid_t waitpid(pid_t pid, int *status, int options);
    
           int waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options);
    

    status参数:
    是一个整型数指针
    非空:
    子进程退出状态放在它所指向的地址中。
    空:
    不关心退出状态

    代码修改:
    在父进程中加wait(NULL);
    结果:

    Warning: bad ps syntax, perhaps a bogus '-'? See http://procps.sf.net/faq.html
    book      7233  0.5  0.0   4172   352 pts/3    S+   18:26   0:00 ./a.out
    book      7236  0.0  0.0  13600   936 pts/6    S+   18:26   0:00 grep --color=auto a.out
    
    

    如何收集子进程的退出状态?
    父进程等待子进程退出并收集子进程的退出状态

    在这里插入图片描述
    检查wait和waitpid所返回的终止状态的宏
    例子:

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    
    int main() {
        pid_t pid;
        int cnt = 0;
        pid = fork();
        int status = 10;
        if (pid > 0) {
                wait(&status);
                printf("child quit, child status = %d\n", WEXITSTATUS(status));
            while (1) {
    
                printf("this is father, pid=%d\n", getpid());
                sleep(1);
                printf("cnt=%d\n", cnt);
            }
        } else if (pid == 0) {
            while (1) {
                printf("this is child, pid=%d, cnt=%d\n", getpid(), cnt);
                    cnt++;
                if (cnt == 3) {
                    exit(3);
                }
            }
        }
        return 0;
    }
    
    

    结果:

    this is child, pid=7272, cnt=0
    this is child, pid=7272, cnt=1
    this is child, pid=7272, cnt=2
    child quit, child status = 3
    
    

    父进程等待子进程退出(二)(waitpid)

    waitpid原型:

    pid_t waitpid(pid_t pid, int *status, int options);
    
    • 如果其所有子进程都还在运行,则阻塞。
    • 如果一个子进程已终止,正等待父进程获取其终止状态,则取得该子进程的终止状态立即返回。
    • 如果它没有任何子进程,则立即出错返回。

    区别:wait使调用者阻塞,waitpid有一个选项,可以使调用者不阻塞。

    在这里插入图片描述

    例子:

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    
    int main() {
        pid_t pid;
        int cnt = 0;
        pid = fork();
        int status = 10;
        if (pid > 0) {
                //wait(&status);
                waitpid(pid, &status, WNOHANG);
            printf("child quit, child status = %d\n", WEXITSTATUS(status));
            while (1) {
    
                printf("this is father, pid=%d\n", getpid());
                sleep(1);
                printf("cnt=%d\n", cnt);
            }
        } else if (pid == 0) {
            while (1) {
                printf("this is child, pid=%d, cnt=%d\n", getpid(), cnt);
                    cnt++;
                if (cnt == 3) {
                    exit(3);
                }
            }
        }
        return 0;
    }
    
    

    结果:

    child quit, child status = 0
    this is father, pid=7461
    this is child, pid=7462, cnt=0
    this is child, pid=7462, cnt=1
    this is child, pid=7462, cnt=2
    cnt=0
    
    

    父子进程是一起运行的,没有等待

    孤儿进程(面试题)
    父进程如果不等待子进程退出,在子进程之前就结束了自己的“生命”,此时子进程叫做孤儿进程

    Linux为了避免系统存在过多孤儿进程,init进程收留孤儿进程,变成孤儿进程的父进程
    例子:

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    
    int main() {
        pid_t pid;
        int cnt = 0;
        pid = fork();
        int status = 10;
        if (pid > 0) {
                printf("this is father, pid=%d\n", getpid());
                
            
        } else if (pid == 0) {
            while (1) {
                printf("this is child, pid=%d, cnt=%d, myfather id = %d\n", getpid(), cnt, getppid());
                    cnt++;
                if (cnt == 3) {
                    exit(3);
                }
            }
        }
        return 0;
    }
    

    结果:

    this is father, pid=7510
    this is child, pid=7511, cnt=0, myfather id = 1
    this is child, pid=7511, cnt=1, myfather id = 1
    this is child, pid=7511, cnt=2, myfather id = 1
    
    
    getppid()//可以获取父进程的pid
    

    exec族函数

    为什么要用exec函数,有什么作用

    1. 一个父进程希望复制自己,使父、子进程同时执行不同的代码段。这在网络服务进程中是常见的——父进程等待客户端的服务请求。当这种请求到达时,父进程调用fork,使子进程处理此请求。父进程则继续等待下一个服务请求到达。
    2. 一个进程要执行一个不同的程序。这队shell是常见的情况。在这种情况下,子进程从fork返回后立即调用exec
      参考博文:
      https://blog.csdn.net/u014530704/article/details/73848573
    #include <stdio.h>
    
    int main(int argc, char *argv[])
    {
        int i = 0;
        for(i=0; i<argc; i++)
        {
            printf("argv[%d]:%s\n", i, argv[i]);
        }
    
        return 0;
    }
    

    结果:

    argv[0]:./echoarg
    

    加参数

    ./echoarg file1 file2
    

    结果:

    argv[0]:./echoarg
    argv[1]:file1
    argv[2]:file2
    
    

    如果exec调用失败
    例子:

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    int main(void)
    {
        printf("before execl\n");
        if(execl("./bin/echoarg","abc",NULL)==-1)
        {
            printf("execl failed!\n");
        
            perror("why");
        }
        printf("after execl\n");
    
        return 0;
    }
    

    结果:

    before execl
    execl failed!
    why: No such file or directory
    after execl
    

    注意路径,修改代码:

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    int main(void)
    {
        printf("before execl\n");
        if(execl("./echoarg","abc",NULL)==-1)
        {
            printf("execl failed!\n");
        
            perror("why");
        }
        printf("after execl\n");
    
        return 0;
    }
    

    结果:

    before execl
    argv[0]:abc
    
    

    ls如何获取
    使用

    whereis ls
    
    ls: /bin/ls /usr/share/man/man1/ls.1.gz
    

    例子:

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    int main(void)
    {
        printf("before execl\n");
        if(execl("/bin/ls","ls", NULL, NULL)==-1)
        {
            printf("execl failed!\n");
        
            perror("why");
        }
        printf("after execl\n");
    
        return 0;
    }
    

    结果:

    before execl
    a.out	  demo11.c  demo2.c  demo4.c  demo6.c  demo8.c	echoarg    mypid  pid.c
    demo10.c  demo1.c   demo3.c  demo5.c  demo7.c  demo9.c	echoarg.c  mypro  pro
    
    

    将代码修改:

    if(execl("/bin/ls","ls", "-l", NULL)==-1)
    

    结果截取部分:

    before execl
    total 116
    -rwxrwxr-x 1 book book 8481 Sep 26 19:40 a.out
    -rw-rw-r-- 1 book book  269 Sep 26 19:31 demo10.c
    -rw-rw-r-- 1 book book  273 Sep 26 19:37 demo11.c
    -rw-rw-r-- 1 book book  273 Sep 26 19:40 demo12.c
    -rw-rw-r-- 1 book book  272 Sep 26 12:17 demo1.c
    -rw-rw-r-- 1 book book  471 Sep 26 12:34 demo2.c
    -rw-rw-r-- 1 book book  341 Sep 26 13:20 demo3.c
    
    

    获取系统时间,简易版:

    1. date
    book@book-virtual-machine:~/dlf/20190926$ date
    Thu Sep 26 19:46:30 CST 2019
    
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    int main(void)
    {
        printf("this pro get system date:\n");
        if(execl("/bin/date","date", NULL, NULL)==-1)
        {
            printf("execl failed!\n");
        
            perror("why");
        }
        printf("after execl\n");
    
        return 0;
    }
    

    结果:

    this pro get system date:
    Thu Sep 26 19:45:58 CST 2019
    

    此时路径都是绝对路径,如果不知道路径将找不到这时候该怎么办?
    例子:
    将execl改成execlp

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    int main(void)
    {
        printf("this pro get system date:\n");
        if(execlp("ps","ps", NULL, NULL)==-1)
        {
            printf("execl failed!\n");
        
            perror("why");
        }
        printf("after execl\n");
    
        return 0;
    }
    

    结果:

      PID TTY          TIME CMD
     3665 pts/3    00:00:04 bash
     8245 pts/3    00:00:00 ps
    
    

    解析:
    当前环境变量

    echo $PATH
    

    结果:

    /usr/lib/lightdm/lightdm:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/opt/FriendlyARM/toolschain/4.5.1/bin:/home/book/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin
    

    不同路径下,不能够找到该文件,如何办?
    修改环境变量:
    (将需要的路径添加进去)

     export PATH=$PATH:/home/book
    

    即使是在本路径下没有该文件也可以进行编译

     echoarg aa bb
    

    结果:

    argv[0]:echoarg
    argv[1]:aa
    argv[2]:bb
    

    不仅如此所有在环境变量下的可执行文件都可以被执行

    execvp使用:

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    int main(void)
    {
        char *argv[] = {"ps", "-l", NULL};
        printf("this pro get system date:\n");
        if(execvp("ps",argv)==-1)
        {
            printf("execl failed!\n");
        
            perror("why");
        }
        printf("after execl\n");
    
        return 0;
    }
    

    execv的使用:需要加绝对路径

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    int main(void)
    {
        char *argv[] = {"ps", "-l", NULL};
        printf("this pro get system date:\n");
        if(execv("/bin/ps",argv)==-1)
        {
            printf("execl failed!\n");
        
            perror("why");
        }
        printf("after execl\n");
    
        return 0;
    }
    

    exec族函数配合fork的使用

    实现功能,当父进程监测到输入为1的时候,把子进程把配置文件的字段值修改掉。

    例子1:

    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <stdio.h>
    #include <string.h>
    #include <unistd.h>
    #include <stdlib.h>
    
    int main() {
        pid_t pid;
        int data = 10;
        while (1) {
            printf("please input a data\n");
            scanf("%d", &data);
            if (data == 1) {
                pid = fork();
                if(pid > 0)
                {
                    wait(NULL);
                }
                if (pid == 0) {
                    char *readBuf = NULL;
    
                    int fdSrc = open("TEST.config", O_RDWR);
    
                    int size = lseek(fdSrc, 0, SEEK_END);
    
                    lseek(fdSrc, 0, SEEK_SET);
                    readBuf = (char *)malloc(sizeof(char) * size + 8);
                    int n_read = read(fdSrc, readBuf, size);
    
                    char *p = strstr(readBuf, "LENG=");
                    if (p == NULL) {
                        printf("not found\n");
    
                        exit(-1);
                    }
                    p = p + strlen("LENG=");
                    *p = '5';
    
                    lseek(fdSrc, 0, SEEK_SET);
                    int n_write = write(fdSrc, readBuf, strlen(readBuf));
    
                    close(fdSrc);
                }
            } else {
                printf("wait, do nothing\n");
            }
        }
    
        return 0;
    }
    

    结果:

    cat TEST.config //之前
    SPEED=3
    LENG=9
    SCORE=9
    LEVEL=5
    
    cat TEST.config //之后
    SPEED=3
    LENG=5
    SCORE=9
    LEVEL=5
    
    

    例子2:
    需要调用的可执行文件

     gcc demo11.c -o changeData
    
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <stdio.h>
    #include <string.h>
    #include <unistd.h>
    #include <stdlib.h>
    
    int main() {
        pid_t pid;
        int data = 10;
        while (1) {
            printf("please input a data\n");
            scanf("%d", &data);
            if (data == 1) {
    
                pid = fork();
                int fdSrc;
                if(pid > 0)
                {
                    wait(NULL);
                }
                if (pid == 0) {
    
                    execl("./changeData", "changeData", "TEST.config", NULL);
                }
            } else {
                printf("wait, do nothing\n");
            }
        }
    
        return 0;
    }
    

    结果:

    SPEED=3
    LENG=8
    SCORE=9
    LEVEL=5
    
    SPEED=3
    LENG=5
    SCORE=9
    LEVEL=5
    
    

    system函数

    参考博客:
    https://www.cnblogs.com/leijiangtao/p/4051387.html

    system()函数的返回值如下:
    成功,则返回进程的状态值;当sh不能执行时,返回127;失败返回-1;

    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <stdio.h>
    #include <string.h>
    #include <unistd.h>
    #include <stdlib.h>
    a
    int main() {
        pid_t pid;
        int data = 10;
        while (1) {
            printf("please input a data\n");
            scanf("%d", &data);
            if (data == 1) {
    
                pid = fork();
                int fdSrc;
                if(pid > 0)
                {
                    wait(NULL);
                }
                if (pid == 0) {
    
                    system("./changeData TEST.config");
                }
            } else {
                printf("wait, do nothing\n");
            }
        }
    
        return 0;
    }
    

    结果:

    SPEED=3
    LENG=0
    SCORE=9
    LEVEL=5
    
    SPEED=3
    LENG=5
    SCORE=9
    LEVEL=5
    

    编译方式

    ./xxx
    sh -c ./xxx
    

    例子:

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    
    int main(void) {
        printf("this pro get system date:\n");
        if (system("ps") == -1) {
            printf("execl failed!\n");
            error("why");
        }
        printf("after execl\n");
        return 0;
    }
    

    结果:

    this pro get system date:
      PID TTY          TIME CMD
     3991 pts/3    00:00:03 bash
     5320 pts/3    00:00:00 a.out
     5321 pts/3    00:00:00 sh
     5322 pts/3    00:00:00 ps
    after execl
    

    如果找不到:

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    
    int main(void) {
        printf("this pro get system date:\n");
        if (system("ps11") == -1) {
            printf("execl failed!\n");
            error("why");
        }
        printf("after execl\n");
        return 0;
    }
    

    结果:

    this pro get system date:
    sh: 1: ps11: not found
    after execl
    

    并不会打印我们erron的why

    sh -c ps11
    sh: 1: ps11: not found
    
    

    popen函数

    比system在应用中的好处:可以获取运行的输出结果
    例:1:

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    
    int main(void) {
        char ret[1024] = {0};
        system("ps");
        printf("ret=%s\n", ret);;
        return 0;
    }
    

    结果:

      PID TTY          TIME CMD
     3991 pts/3    00:00:04 bash
     5523 pts/3    00:00:00 a.out
     5524 pts/3    00:00:00 sh
     5525 pts/3    00:00:00 ps
    ret=
    

    例子2:

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    
    int main(void) {
        char ret[1024] = {0};
        FILE *fp;
        fp = popen("ps", "r");
        int nread = fread(ret, 1, 1024, fp);
        printf("read ret %d byte, ret=%s\n", nread, ret);
        return 0;
    }
    

    结果:

    read ret 141 byte, ret=  PID TTY          TIME CMD
     3991 pts/3    00:00:04 bash
     5569 pts/3    00:00:00 a.out
     5570 pts/3    00:00:00 sh
     5571 pts/3    00:00:00 ps
    
    
    

    如果将printf注释掉,将不会打印任何信息。

    (面试题)问:请简述进程和线程的区别(进程和线程什么关系/进程线程优缺点)

    答:

    根本区别:

    进程是操作系统资源分配的基本单位,而线程是任务调度和执行的基本单位

    在开销方面:

    每个进程都有独立的代码和数据空间(程序上下文),程序之间的切换会有较大的开销;线程可以看做轻量级的进程,同一类线程共享代码和数据空间,每个线程都有自己独立的运行栈和程序计数器(PC),线程之间切换的开销小。

    所处环境:

    在操作系统中能同时运行多个进程(程序);而在同一个进程(程序)中有多个线程同时执行(通过CPU调度,在每个时间片只有一个线程执行)。

    内存分配方面:

    系统在运行的时候会为每个进程分配不同的内存空间;而对线程而言,除了CPU外,系统不会为线程分配内存(线程所使用的资源来自其所属进程的资源),线程组之间可以共享资源。

    包含关系:

    没有开辟线程的进程可以看做是单线程的,一个进程至少有一个线程,如果一个进程内有多个线程,则执行过程不是一条线的,而是多条线(线程)共同完成的;线程是进程的一部分,所以线程也被称为轻权线程或者轻量级进程。

    展开全文
  • 1、介绍Linux 3.x之后内核在底层BSP上做了哪些优化。2、如何提供操作系统的运行节拍。3、中断控制器驱动以及它如何为驱动提供标准接口。4、多核SMP芯片启动。5、作为Linux运行底层基础设施GPIO、pinctrl(管脚...
    本章知识点

    在一个新的ARM SoC上,如何移植Linux。

    1、介绍Linux 3.x之后的内核在底层BSP上做了哪些优化。

    2、如何提供操作系统的运行节拍。

    3、中断控制器驱动以及它如何为驱动提供标准接口。

    4、多核SMP芯片的启动。

    5、作为Linux运行底层基础设施的GPIO、pinctrl(管脚控制器)、时钟和dmaengine驱动。

    本章有助于工程师理解驱动调用的底层API的来源,以及直接进行Linux的平台移植。

    20.1 ARM Linux底层驱动的组成和现状

        让Linux在一个全新的ARM SoC上运行,需提供大量的底层支撑,如定时器节拍、中断控制器、SMP启动、CPU热插拔以及底层的GPIO、时钟、pinctrl和DMA硬件的封装等。定时器节拍为Linux基于时间片的调度机制以及内核和用户空间的定时器提供支撑,中断控制器的驱动则使得Linux内核的工程师可以直接调用local_irq_disable()、disable_irq()等通用的中断API,SMP启动支持则用于让SoC内部的多个CPU核都投入运行,CPU热插拔则运行运行时挂载或拔除CPU

    在GPIO、时钟、pinctrl和DMA驱动方面,在Linux 2.6时代,内核已或多或少有GPIO、时钟等底层驱动的架构,但是核心层的代码太薄弱,各SoC在这些基础设施实现方面存在巨大差异,而且每个SoC仍然需要实现大量的代码。pinctrl和DMA则最为混乱,几乎各家公司都定义了自己独特的实现和API。

    社区必须改变这种局面,Linux社区在2011年后进行了如下工作,这些工作在目前的Linux内核中基本准备就绪:

    1、STEricsson公司的工程师Linus Walleij提供新的pinctrl驱动架构,内核中新增加一个drivers/pinctrl目录,支撑SoC上的引脚复用,各个SoC的实现代码统一放入该目录。

    2、TI公司的工程师Mike Turquette提供通用时钟框架,让具体SoC实现clk_ops()成员函数,并通过
    clk_register()、clk_register_clkdev()注册时钟源以及源与设备的对应关系,具体的时钟驱动都统一迁

    移到drivers/clk目录中。

    3、建议各SoC统一采用dmaengine架构实现DMA驱动,该架构提供通用的DMA通道API,如

    dmaengine_prep_slave_single()、dmaengine_submit()等,要求SoC实现dma_device的成员函数,实现代码统一放入drivers/dma目录中。

    4、在GPIO方面,drivers/gpio下的gpiolib已能与新的pinctrl完美共存,实现引脚的GPIO和其他功能之间的复用,具体的SoC只需实现通用的gpio_chip结构体的成员函数

    经过以上工作,基本上就把芯片底层基础架构方面的驱动架构统一了,实现方法也统一了。目前GPIO、时钟、pinmux等都能良好地进行设备树的映射处理,可以方便地在.dts中定义一个设备要的时钟、pinmux引脚以及GPIO。

    除了上述基础设施以外,在将Linux移植入新的SoC过程中,工程师常常强烈依赖于早期的printk功能,内核则提供了相关的DEBUG_LL和EARLY_PRINTK支持,只需要SoC提供商实现少量的回调函数或宏。

    本章主要对上述各个组成部分进行架构上的剖析以及对关键的实现部分的实例分析,以求完整归纳出将Linux移植入新SoC的主要工作。



    展开全文
  • Linux是一个多用户、多任务操作系统系统中通常运行着非常多进程。哪些进程先运行哪些进程后运行,就由进程优先级来控制 二、进程调度方式 在Linux中,线程是由进程来实现,线程可以理解为轻量级的...

    一、为什么会有进程优先级这个概念

        Linux是一个多用户、多任务的操作系统,系统中通常运行着非常多的进程。哪些进程先运行,哪些进程后运行,就由进程优先级来控制

    二、进程调度的方式

        在Linux中,线程是由进程来实现的,线程可以理解为轻量级的进程。因此线程的调度是按照进程的调度方式来进行调度的

     (1)SCHED_OTHER,分时调度策略       

     (2)SCHED_FIFO,实时调度策略,先到先服务

     (3)SCHED_RR,实时调度策略,时间片轮转 

        其中:分时调度策略为Linux系统默认的调度策略

    三、进程优先级查看

        nice值和priority的理解:

        nice值是用户层面的,我们可以通过调整NI值,来影响进程的优先级,范围:-20至19

        PR:内核层面,该值决定进程优先级的执行先后

        PR(new) = PR(old) + NI 

        3.1 top命令 

            PR:进程的优先级

             NI:nice值

        3.2 ps -l

    四、优先级的调整

        4.1 准备运行的程序 :通过nice命令

             nice -n -5 /usr/local/mysql/bin/mysqld &

        4.2 调整正在运行的进程优先级

            renice  值 pid

     

    备注:这里只是简单说明下进程优先级,深度的可以查看《Linux内核设计与实现》,很多博客都是引用这本书来解释的

    展开全文
  • 系统多少进程在运行,其属主是谁? 2. 一个进程打开多少文件?3. 目前锁定了什么文件,4. 哪些进程持有这些锁?系统正在使用什么套接字? 为了提供更为简便方法访问内核信息,许多现代UNIX实现提供了一个/proc...
  • 一、环境准备 1.开启CentOS7虚拟机,以root用户登录 课前回顾: 1.Linux中命令执行依赖于解释器,默认解释器是哪个程序? /bin/bash 2.如何结束当前正在运行的命令,快捷键是?...4.ls常用选项有哪些?...
  • Unit1:关于Linux的基础知识以及常用命令 学习目标: 1、 了解什么是操作系统 2、 熟悉Linux的作用以及好处 3、 熟练掌握linux常见命令 4、 掌握有关面试试题 ...常见的操作系统有哪些 作用: 1> 是现代计算机系
  • 2.如何查看系统有哪些进程?3.什么是进程标识符?4.什么是父进程?什么是子进程?5.c语言存储空间是如何分配?三目录 一、基础概念 1.什么是程序,什么是进程,有什么区别? 程序是一个静态概念,我们用c语言...
  • 但是我必须承认:在计算机行业的巨头们认识到它的重要性之前,Linux并没有引起人们的注意(我最喜欢的一幅幽默画是:一只象征着Linux的企鹅被绑在一架巨大的涂“IBM”标志的喷气机引擎上,画面的标题是“怎样才能...
  • 今天介绍进程进程管理,子进程创建以及进程资源回收 首先什么是进程?...操作系统为了和管理进程,会一个控制块来记录进程用到了哪些资源。叫做PCB块。 每一个进程都自己一个ID叫做PID。 用以下
  • Linux的特点Linux与其他PC操作系统的比较Linux与MS—DOS比较Linux与Windows比较Linux与UNIX比较第二章系统的运行级别运行级切换Systemd 服务管理系统关机命令 Linux考试复习篇(一、二章) 第一章 什么是开源软件? ...
  • Linux管理员指南

    2009-02-26 16:11:56
    但是我必须承认:在计算机行业的巨头们认识到它的重要性之前,Linux并没有引起人们的注意(我最喜欢的一幅幽默画是:一只象征着Linux的企鹅被绑在一架巨大的涂“IBM”标志的喷气机引擎上,画面的标题是“怎样才能...
  • linux管理员指南

    2009-12-30 11:20:05
    但是我必须承认:在计算机行业的巨头们认识到它的重要性之前,Linux并没有引起人们的注意(我最喜欢的一幅幽默画是:一只象征着Linux的企鹅被绑在一架巨大的涂“IBM”标志的喷气机引擎上,画面的标题是“怎样才能...
  • 10分钟教你玩转Linux

    千次阅读 2014-07-07 11:28:17
    用习惯window的用户,突然转去用Linux系统,一般会很不习惯,尤其面对Linux的命令行界面(CLI)。本文试图用10分钟教会你如何使用Linux。 在window中,我们最常用的一些操作:打开“我的电脑”浏览磁盘,打开文件...
  • linux.chm文档

    2015-07-07 06:37:39
    find /home/user1 -name \*.bin 在目录 '/ home/user1' 中搜索带'.bin' 结尾文件 find /usr/bin -type f -atime +100 搜索在过去100天内未被使用过执行文件 find /usr/bin -type f -mtime -10 搜索在10天内...
  • linux_启动脚本次序.doc

    2011-01-25 14:58:33
     至于在每个运行级中将运行哪些守护进程,用户可以通过chkconfig或setup中”System Services”来自行设定。常见守护进程:  amd:自动安装NFS守护进程  apmd:高级电源管理守护进程  arpwatch:记录日志并...
  • 目前在用户程序开发中,...进程资源到底有哪些,如何体现?线程为什么是轻量级的运行单位?如何体现? 进程和线程几乎共享所有资源,包括代码/数据/进程空间/打开文件,线程拥有自己寄存器和栈,这些概念上.
  • at ip time 程序名(或一个命令) /r 在某时间运行对方某程序并重新启动计算机 finger username @host 查看最近有哪些用户登陆 telnet ip 端口 远和登陆服务器,默认端口为23 open ip 连接到IP(属telnet登陆后...
  • linux_新手管理员手册(PDF)

    千次下载 热门讨论 2006-05-09 09:54:53
    0.13 但是Linux 可能会被“肢解”成很多不同的系统.............................. 9 0.14 Linux 只是一个小帮派.................................................... 9 0.15 Linux 总体拥有费用(TCO)太高.........
  • 高级进程管理之处理器亲和性

    千次阅读 2010-05-09 13:48:00
    两项挑战源自此责任:调度程序必须想办法充分利用系统所有处理器,因为当一个进程已就绪等待运行,却一个CPU闲置一旁,这显然没有效率。 然而一个进程一旦被安排在某个CPU上运行,往后进程调度程序也会将...
  • 操作系统(内存管理)

    热门讨论 2009-09-20 12:55:25
    基于 UNIX 的系统有两个可映射到附加内存中的基本系统调用: brk: brk() 是一个非常简单的系统调用。还记得系统中断点吗?该位置是进程映射的内存边界。 brk() 只是简单地将这个位置向前或者向后移动,就可以向...
  • Stateful Session Bean 与 Stateless Session Bean ,这两种 Session Bean都可以将系统逻辑放在 method之中执行,不同是 Stateful Session Bean 可以记录呼叫者状态,因此通常来说,一个使用者会一个相对应...

空空如也

空空如也

1 2 3 4 5 ... 7
收藏数 129
精华内容 51
关键字:

linux的系统运行级有哪些

linux 订阅