Linux学习第七天

本文介绍了Linux进程控制的相关概念,包括开机启动进程、进程身份(uid、gid、euid、egid)、权限提升(如chmod u+s)、后台执行进程、查看进程状态(如ps、top)以及进程调度策略。还探讨了如何修改用户id、进程优先级调整(renice)、定时任务(crontab)和文件系统(如NFS)。此外,讲解了fork、exec家族函数在进程创建和替换中的应用,并讨论了孤儿进程和僵尸进程的处理。最后,涉及了多线程写文件和进程间通信的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、进程控制

1、开机后bootloader将系统的第一个进程启动了起来,bootloader是烧制在bios上的

2、第一个例子:getpid

 

#include"func.h"

int main(int argc,char* argv[])

{

 

    pid_t pid,ppid;

    pid=getpid();

    ppid=getppid();

    printf("pid=%d,ppid=%d",pid,ppid);

    return 0;

}

 

3、一个进程有4个身份:真实用户id、真实组id;有效用户id、有效组id

(1)真实用户id:getuid()

(2)真实组id:getgid()

(3)有效用户id:geteuid()

(4)有效组id:getegid()

 

4、第二个例子:gid和uid的例子、euid和egid的例子

#include"func.h"

 

int main()

{

    pid_t uid,gid,euid,egid;

    uid=getuid();

    gid=getgid();

    euid=geteuid();

    egid=getegid();

    printf("uid=%d,gid=%d,euid=%d,egid=%d",uid,gid,euid,egid);

    return 0;

}

 

5、第三个例子modify_file.c

 

#include <func.h>

 

int main(int argc,char* argv[])

{

    printf("uid=%d,gid=%d,euid=%d,egid=%d\n",getuid(),getgid(),geteuid(),getegid());

    int fd=open("file",O_RDWR);

    ERROR_CHECK(fd,-1,"open");

    write(fd,"hello",5);

    close(fd);

    return 0;

}

 

 

6、s是权限提升

Chmod u+s a.out          该命令可以实现权限提升
权限提升:在权限控制中,使用权限提升后,也就是设置了该属性后,用户运行a.out时,a.out进程的有效用户身份将不再是运行a.out的用户,而是a.out文件的所有者。

 

7、红色的命令(可以实现权限提升):sudo、su、chmod u+s

命令chmod g+s a.out 对同组用户进行权限提升

命令chmod o+t a.out 增加粘滞键,增加一些权限检查

 

8、如何修改真实用户id?

接口setuid,该命令只有sudo权限才可以执行

sudo实现的原理,提升euid的权限

 

使用命令man setuid获取更多帮助

  int setuid(uid_t uid);

  int setgid(gid_t gid);
 int seteuid(uid_t euid);

 int setegid(gid_t egid);

 

9、在执行程序时,如果想让进城在后台执行,可以使用命令 ./a.out &         该命令会返回进程的PID

同一个程序可以启动多次,故还可以继续使用命令./a.out &

 

10、使用top查看动态进程后,进程状态的标志如下:

R 两次采样之间是不是有时间片消耗

S 睡眠

T 暂停

Z 僵尸进程

 

11、小技巧:

(1)使用命令ps -elf,可以查看进程状态

(2)通过who命令可以查看当前有几个用户正在登陆及当前登陆用户的详细信息

(3)命令which sudo ,可以查看sudo命令所在的路径

(4)在实际使用中,用户环境分为:生产环境和测试环境

(5)使用命令free可以查看磁盘当前使用状态

(6)查看某进程详细信息的命令ps -elf|grep [pid/进程名]

 

12、如何将其他用户踢出去?

(1)使用命令ps -elf|grep luke

(2)将某异常用户对应的进程杀掉,即可将该用户退出

(3)杀掉进程使用命令kill -9 [pid]

 

13、ps的常用命令

(1)ps -elf

 

(2)ps -aux

看CPU的使用量、没存使用量、stat状态

 

(3)top

显示前20条进程,动态的改变

 

(4)搜索进程使用命令ps -elf|grep a.out

 

(5)Ubuntu下,优先级有140个优先级(PRI)。范围是-40—99

 

(6)调度策略:

实时          SCHED_FIFO      SCHED_RR        -40-59       高优先级的先运行

普通调度策略    CFS        SCHED_OTHER       60-99

 

14、如何改变进程优先级,使用命令renice -n +19

降低优先级,优先级号越低,优先级越高。因此如果优先级号变大,那么优先级降低

 

使用命令renice -n +40 -p -12234    

 

杀死进程kill -9 [pid],或者使用命令pkill [进程名,例如a.out]

 

 

15、命令crontab,相当于windows下的定时任务,可以设置定时关机等功能

 

16、NFS是网络文件系统Network File System

 

 

17、在使用wait函数时,会提示缺少wait的定义,其实是缺少头文件,应该在func.h中增加两个头文件#include<sys/wait.h>

#include<sys/types.h>

 

 

18、在测试fork的程序中,是父进程输出快,还是子进程输出快?

答案是:父进程输出快,子进程被创建后,需要重新去申请时间片,故还要重新去调度队列末尾等待被调度。

 

19、代码fork_stack.c

 

#include"func.h"

 

int main(int argc,char*argv[])

{

    pid_t pid;

    int iStack=10;

    pid=fork();

    if(pid==0)

    {

        printf("I am child ,my pid =%d,ppid=%d ,iStack=%d, %p\n",getpid(),getppid(),iStack,&iStack);

 

           

    }

    else

    {

        printf("I am parent my pid=%d,mychildpid=%d,iStack=%d\n",getpid(),pid,iStack);

        iStack=5;

        printf("I am parent after modify my iStack%d,%p\n",iStack,&iStack);

        sleep(1);

    }

    return 0;

}

 

 

 

20、代码例子fork_malloc.c

 

#include"func.h"

int main(int argc,char* argv[])

{

    pid_t pid;

    char *pMalloc=(char*)malloc(20);

    strcpy(pMalloc,"hello");

    pid=fork();

    if(pid==0)

    {

        printf("I am child,mypid=%d,myppid=%d,%s,%p\n",getpid(),getppid(),pMalloc,pMalloc);

 

    }

    else

    {

        printf("I am parent mypid=%d,mychildpid=%d,%s\n",getpid(),pid,pMalloc);

        pMalloc[0]='H';

        printf("I am parent after modify %s,%p\n",pMalloc,pMalloc);

        sleep(1);

    }

    return 0;

}

 

 

 

21、如何验证父进程和子进程的文件描述符是否一致,例子fork_open.c

 

 

#include <func.h>

 

int main(int argc,char* argv[])

{

    pid_t pid;

    int fd=open(argv[1],O_RDWR);

    ERROR_CHECK(fd,-1,"open");

    pid=fork();

    if(0==pid)

    {

        printf("I am child mypid=%d,myppid=%d\n",getpid(),getppid());

        write(fd,"niuniu",6);

    }else{

        printf("I am parent mypid=%d,mychildpid=%d\n",getpid(),pid);

        lseek(fd,5,SEEK_SET);

        printf("I am parent seek success\n");

        sleep(1);

    }

    return 0;

}

 

 

根据这个例子,证明了父进程运行速度较快,而子进程运行因为需要重新去队列中排队等待处理机,所以慢了一点

 

22、验证代码例子fork_open2.c,可以提高文件读写速度(但是往往磁盘读写速度才是瓶颈)

 

#include <func.h>

 

int main(int argc,char* argv[])

{

    pid_t pid;

    int fd;

    pid=fork();

    if(0==pid)

    {

        fd=open(argv[1],O_RDWR);

        ERROR_CHECK(fd,-1,"open");

        printf("I am child mypid=%d,myppid=%d\n",getpid(),getppid());

        write(fd,"niuniu",6);

    }else{

        fd=open(argv[1],O_RDWR);

        ERROR_CHECK(fd,-1,"open");

        printf("I am parent mypid=%d,mychildpid=%d\n",getpid(),pid);

        lseek(fd,5,SEEK_SET);

        printf("I am parent seek success\n");

        sleep(1);

    }

    return 0;

}

 

 

 

23、多线程写文件,使用mmap,使多个线程或进程,对内存进行操作

 

24、execl是直接将磁盘上的代码,直接复制到当前进程的代码段。这时候程序就会按照新的代码去执行

 

25、代码execl.c和print.c文件,两个文件是调用关系

 

#include <func.h>

 

int main(int argc,char* argv[])

{

    sleep(10);

    execl("./print","niuniu","123","456",NULL);

    printf("you can't see me\n");

    return 0;

}

 

 

 

Execl("./print","niuniu","123","456",NULL);

会使用niuniu作为进程名

execl如果执行失败,是可以看到那句you can't see me

 

26、execl有6个兄弟,他们实现的功能都相似,只是写法不太一样

 

27、代码例子execv.c

 

(1)execv.c内容

#include <func.h>

 

int main(int argc,char* argv[])

{

    sleep(10);

    char *const args[]={"niuniu","123","456",NULL};

    execv("./print",args);

    printf("you can't see me\n");

    return 0;

}

 

(2)print.c内容

#include <func.h>

 

int main(int argc,char* argv[])

{

    int i;

    for(i=0;i<argc;i++)

    {

        puts(argv[i]);

    }

    printf("I am print process\n");

    while(1);

    return 0;

}

 

 

 

28、孤儿进程:父进程先于子进程退出,这时子进程就变成了一个孤儿进程,该进程被init进程接管

 

29、子进程已经结束,但父进程还在忙碌,没有回收子进程的内容,这时候子进程就会编程一个僵尸进程;僵尸进程的状态代码是Z,僵尸进程的进程状态是不可以再改变的

 

30、如何避免子进程变成僵尸进程?父进程应该是用wait函数定期回收子进程

但是wait一次执行,只能回收一次

 

31、代码示例wait.c|下午第三个视频

 

wait的返回值是子进程的pid

WIFEXITED是一个宏操作

怎么看一个参数是宏还是函数?

 

32、代码例子waitpid.c|下午第三个视频

 

33、exit和_exit的区别

(1)exit会调用退出处理函数,清空I/O缓冲

(2)_exit不会调用退出处理函数,也不会清空I/O缓冲,会直接调用exit系统调用退出

 

34、abort函数

用户进程终止

 

代码例子abort.c

 

#include <func.h>

void print()

{

    printf("I am print");

    abort();

}

int main(int argc,char* argv[])

{

    print();

    printf("after print\n");

    return 0;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值