alin的学习之路(Linux系统编程:五)(目录操作、进程相关概念)

alin的学习之路(Linux系统编程:五)(目录操作、进程相关概念)

1. 目录操作

1. 查看工作目录 getcwd

char *getcwd(char *buf, size_t size)
功能:
    获取当前工作目录(绝对路径)

参数:
    buf 保存工作路径的缓冲区
    size 指定buf可以存储字节数

返回值:
    成功 buf的起始地址
    失败 NULL
#include <stdio.h>
#include <unistd.h>
#define SIZE 32
int main()
{
    char buf[SIZE] = {0};
    char* p = getcwd(buf,SIZE);
    if(NULL == p)
    {
        perror("getcwd");
        return 1;
    }

    printf("%s\n",buf);
    return 0;
}

2. 改变工作目录 chdir

int chdir(const char *path);
功能:
    改变当前进程工作目录

参数:
    path 相对路径或者绝对路径

返回值:
    成功 0
    失败 -1
#include <stdio.h>
#include <unistd.h>
#define SIZE 32
int main()
{
    char buf[SIZE] = {0};
    char* p = getcwd(buf,SIZE);
    if(NULL == p)
    {
        perror("getcwd");
        return 1;
    }

    printf("%s\n",buf);
    return 0;
}

itcast@ubuntu:~/classcode/day05$ ^C
itcast@ubuntu:~/classcode/day05$ cat 2chdir.c
#include <stdio.h>
#include <unistd.h>
#define SIZE 32
#include <string.h>
int main()
{
    char *p = NULL;
    char buf[SIZE];

    memset(buf, 0, SIZE);
    //获取当前进程工作路径
    p = getcwd(buf, SIZE);
    if (NULL == p)
    {
        perror("getcwd");
        return 1;
    }

    printf("buf: %s\n", buf);
    int ret = chdir("/home/itcast");
    if(ret == -1)
    {
        perror("chdir");
        return 1;
    }

    p = getcwd(buf, SIZE);
    if (NULL == p)
    {
        perror("getcwd");
        return 1;
    }
    printf("buf: %s\n", buf);
    return 0;
}

3.打开目录、关闭目录 opendir\closedir

DIR *opendir(const char *name);
功能:
    打开目录
参数:
    name: 目录绝对路径或者相对路径

返回值:
    成功 DIR指针类型
    失败 NULL

int closedir(DIR *dirp);
功能:
    关闭目录
参数:
    dirp opendir函数的返回值
返回值:
    成功 0
    失败 -1
#include <stdio.h>
#include <sys/types.h>
#include <dirent.h>

int main()
{
    DIR * d = NULL;
    d = opendir("/home/itcast");
    if(NULL == d)
    {
        perror("opendir");
        return 1;
    }
    printf("打开目录成功\n");
    closedir(d);
    printf("关闭目录成功\n");

    return 0;
}

4. 读目录 readdir

struct dirent *readdir(DIR *dirp)
功能:
    读目录
参数:
    dirp opendir函数的返回值
返回值:
    成功: 结构体指针
    失败: NULL

    struct dirent {
        ino_t          d_ino;       /* Inode number */
        off_t          d_off;       /* Not an offset; see below */
        unsigned short d_reclen;    /* Length of this record */
        unsigned char  d_type;      /* Type of file; not supported
                                       by all filesystem types */
        char           d_name[256]; /* Null-terminated filename */
    };

    d_type 文件的类型
    d_name 文件名
#include <stdio.h>
#include <sys/types.h>
#include <dirent.h>

int main()
{
    DIR *dir = NULL;
    struct dirent* d;
    //打开目录
    dir = opendir("/home/itcast");
    if (NULL == dir)
    {
        printf("opendir failed...\n");
        return 1;
    }
    while(1)
    {
        d = readdir(dir);
        if(d == NULL)
            break;
        printf("type: %u, name:%s\n",d->d_type,d->d_name);
    }
    closedir(dir);
    return 0;
}

2.时间相关函数

time_t time(time_t *tloc);
功能:
	获取时间 从19701100:00:00到现在经历多少秒
参数:
	tloc time_t类型指针 保存秒数,可以传NULL
返回值:
	成功 返回秒数 从19701100:00:00到现在经历多少秒
    失败 -1

char *ctime(const time_t *timep);
功能:
	时间转换函数 将time_t类型的时间转化为字符串
参数:
	timep time_t指针
返回值:
	成功 字符串格式的时间

struct tm *localtime(const time_t *timep)
功能:
	将time_t类型的时间转化为struct tm*类型的时间
参数:
	timep time_t* 类型
返回值:
	成功 struct tm指针
    失败 (void*)-1

    struct tm {
        int tm_sec;    /* Seconds (0-60) */int tm_min;    /* Minutes (0-59) */ 分钟
        int tm_hour;   /* Hours (0-23) */int tm_mday;   /* Day of the month (1-31) */int tm_mon;    /* Month (0-11) */int tm_year;   /* Year - 1900 */int tm_wday;   /* Day of the week (0-6, Sunday = 0) */ 星期
        int tm_yday;   /* Day in the year (0-365, 1 Jan = 0) */ 一年中第多少天
        int tm_isdst;  /* Daylight saving time */
    };
#include <stdio.h>
#include <time.h>
int main()
{
    time_t t;  //time_t是long int类型
    struct tm* tp;

    t = time(NULL);
    printf("time = %ld\n",t);

    printf("ctime = %s\n",ctime(&t));
    //转化 将秒数转化为年月日时分秒
    tp = localtime(&t);
    if ((void*)-1 == tp)
    {
        perror("localtime");
        return 1;
    }

    printf("tm_sec   %d\n",   tp->tm_sec  );
    printf("tm_min   %d\n",   tp->tm_min  );
    printf("tm_hour  %d\n",   tp->tm_hour );
    printf("tm_mday  %d\n",   tp->tm_mday );
    printf("tm_mon   %d\n",   tp->tm_mon + 1  );
    printf("tm_year  %d\n",   tp->tm_year+ 1900 );
    printf("tm_wday  %d\n",   tp->tm_wday );
    printf("tm_yday  %d\n",   tp->tm_yday );


    //asctime函数
    printf("asctime: %s\n", asctime(tp));


    //gmtime函数
    //转化 将秒数转化为年月日时分秒
    tp = gmtime(&t);
    if ((void*)-1 == tp)
    {
        perror("localtime");
        return 1;
    }

    printf("tm_sec   %d\n",   tp->tm_sec  );
    printf("tm_min   %d\n",   tp->tm_min  );
    printf("tm_hour  %d\n",   tp->tm_hour + 8);
    printf("tm_mday  %d\n",   tp->tm_mday );
    printf("tm_mon   %d\n",   tp->tm_mon + 1  );
    printf("tm_year  %d\n",   tp->tm_year+ 1900 );
    printf("tm_wday  %d\n",   tp->tm_wday );
    printf("tm_yday  %d\n",   tp->tm_yday );

    return 0;
}

时间相关的函数根据manpage中的函数参数可返回值即可学会它们的使用

3. 进程相关概念及命令

1. 进程概念简述

  1. 进程和程序:

    1. 程序是一个可执行文件
    2. 进程是程序执行的过程
    3. 进程的状态是变化的,包括就绪态,运行态和阻塞态
    4. 进程是管理事务的基本单元。
  2. 单道与多道程序

    1. 单道程序:一个进程运行时其他进程阻塞等待
    2. 多道程序:时钟中断多个进程轮流运行
  3. 并行和并发

    1. 并行:任意时刻多个进程同时执行
    2. 并发:任意时刻仅有一个进程执行,多个进程每个进程执行一小段时间,轮流依次执行
  4. MMU:

    MMU是Memory Management Unit的缩写,中文名是内存管理单元,它是中央处理器(CPU)中用来管理虚拟存储器、物理存储器的控制线路,同时也负责虚拟地址映射为物理地址,以及提供硬件机制的内存访问授权,多用户多进程操作系统。

  5. 进程控制块PCB

    1. 进程运行时,内核为进程每个进程分配一个PCB(进程控制块),维护进程相关的信息,Linux内核的进程控制块是task_struct结构体。
    2. 其内部成员有很多,我们掌握以下部分即可:
  • 进程id。系统中每个进程有唯一的id,在C语言中用pid_t类型表示,其实就是一个非负整数。
  • 进程的状态,有就绪、运行、挂起、停止等状态。
  • 进程切换时需要保存和恢复的一些CPU寄存器。
  • 描述虚拟地址空间的信息。
  • 描述控制终端的信息。
  • 当前工作目录(Current Working Directory)。
  • umask掩码。
  • 文件描述符表,包含很多指向file结构体的指针。
  • 和信号相关的信息。
  • 用户id和组id。
  • 会话(Session)和进程组。
  • 进程可以使用的资源上限(Resource Limit)。
  1. 进程的状态

    1. 在三态模型中,进程状态分为三个基本状态,即运行态,就绪态,阻塞态

      在五态模型中,进程分为新建态、终止态,运行态,就绪态,阻塞态

在这里插入图片描述

  1. **①TASK_RUNNING:**进程正在被CPU执行。当一个进程刚被创建时会处于TASK_RUNNABLE,表示己经准备就绪,正等待被调度。

    ②TASK_INTERRUPTIBLE(可中断):进程正在睡眠(也就是说它被阻塞)等待某些条件的达成。一旦这些条件达成,内核就会把进程状态设置为运行。处于此状态的进程也会因为接收到信号而提前被唤醒比如给一个TASK_INTERRUPTIBLE状态的进程发送SIGKILL信号,这个进程将先被唤醒(进入TASK_RUNNABLE状态),然后再响应SIGKILL信号而退出(变为TASK_ZOMBIE状态),并不会从TASK_INTERRUPTIBLE状态直接退出。

    ③TASK_UNINTERRUPTIBLE(不可中断):处于等待中的进程,待资源满足时被唤醒,但不可以由其它进程通过信号或中断唤醒。由于不接受外来的任何信号,因此无法用kill杀掉这些处于该状态的进程。而TASK_UNINTERRUPTIBLE状态存在的意义就在于内核的某些处理流程是不能被打断的。如果响应异步信号,程序的执行流程中就会被插入一段用于处理异步信号的流程,于是原有的流程就被中断了,这可能使某些设备陷入不可控的状态。处于TASK_UNINTERRUPTIBLE状态一般总是非常短暂的,通过ps命令基本上不可能捕捉到。

    **④TASK_ZOMBIE(僵死):**表示进程已经结束了,但是其父进程还没有调用wait4或waitpid()来释放进程描述符。为了父进程能够获知它的消息,子进程的进程描述符仍然被保留着。一旦父进程调用了wait4(),进程描述符就会被释放。

    **⑤TASK_STOPPED(停止):**进程停止执行。当进程接收到SIGSTOP,SIGTSTP,SIGTTIN,SIGTTOU等信号的时候。此外,在调试期间接收到任何信号,都会使进程进入这种状态。当接收到SIGCONT信号,会重新回到TASK_RUNNABLE

  2. stat中的参数意义如下:

    参数 含义
    D 不可中断 Uninterruptible(usually IO)
    R 正在运行,或在队列中的进程
    S(大写) 处于休眠状态
    T 停止或被追踪
    Z 僵尸进程
    W 进入内存交换(从内核2.6开始无效)
    X 死掉的进程
    < 高优先级
    N 低优先级
    s 包含子进程
    + 位于前台的进程组
    l 多线种进程(如CLONE_THREAD, NPTL )

2. 进程相关命令

  1. ps 命令:查看当前系统的进程信息

常用选项:-aux 或 -ef

itcast@ubuntu:~/classcode/day05$ ps -aux
USER         PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root           1  0.0  1.3 168668 12808 ?        Ss   00:44   0:03 /sbin/in
root           2  0.0  0.0      0     0 ?        S    00:44   0:00 [kthread
root           3  0.0  0.0      0     0 ?        I<   00:44   0:00 [rcu_gp]
root           4  0.0  0.0      0     0 ?        I<   00:44   0:00 [rcu_par
root           6  0.0  0.0      0     0 ?        I<   00:44   0:00 [kworker

可以搭配管道和grep使用,查看指定信息

itcast@ubuntu:~/classcode/day05$ ps -aux | grep bash
itcast      1500  0.0  0.5   8540  5352 pts/0    Ss+  00:58   0:00 -bash
itcast      3689  0.0  0.5   8540  5320 pts/1    Ss   01:46   0:00 -bash
itcast     15277  0.0  0.0   6300   740 pts/1    S+   08:52   0:00 grep --color=auto bash
  1. top命令:动态查看当前系统的进程信息,类似Windows的任务管理器
itcast@ubuntu:~/classcode/day05$ top
top - 08:55:10 up  8:10,  2 users,  load average: 0.00, 0.00, 0.00
Tasks: 190 total,   1 running, 189 sleeping,   0 stopped,   0 zombie
%Cpu(s):  0.0 us,  0.3 sy,  0.0 ni, 99.7 id,  0.0 wa,  0.0 hi,  0.0 si,  0.
MiB Mem :    953.3 total,    119.1 free,    242.8 used,    591.4 buff/cache
MiB Swap:   1906.0 total,   1905.2 free,      0.8 used.    549.8 avail Mem

    PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+
    754 root       0 -20  161148   7012   6036 S   0.3   0.7   0:35.77
   3461 root      20   0       0      0      0 I   0.3   0.0   0:43.65
   3688 itcast    20   0   13924   5788   4312 S   0.3   0.6   0:00.41
  15326 itcast    20   0    9248   3784   3260 R   0.3   0.4   0:00.02
      1 root      20   0  168668  12808   8576 S   0.0   1.3   0:03.82
      2 root      20   0       0      0      0 S   0.0   0.0   0:00.01
      3 root       0 -20       0      0      0 I   0.0   0.0   0:00.00
      4 root       0 -20       0      0      0 I   0.0   0.0   0:00.00
  1. kill 命令
    1. 使用方法
      1. kill 进程号
      2. kill -信号编号 进程号
      3. kill -信号宏 进程号
      4. 所以使用kill 必须要得知进程编号,进程编号从ps -aux得来
# sleep second 可以使程序睡眠second秒,用于创建一个进程,并使用kill杀死
# 终端1
itcast@ubuntu:~/classcode/day05$ sleep 1000
Terminated
itcast@ubuntu:~/classcode/day05$ sleep 1000
Killed
itcast@ubuntu:~/classcode/day05$ sleep 1000
Killed

# 终端2
itcast@ubuntu:~/classcode/day05$ ps -aux | grep sleep
itcast     15451  0.0  0.0   5476   592 pts/0    S+   08:59   0:00 sleep 1000
itcast     15460  0.0  0.0   6432   664 pts/1    S+   09:00   0:00 grep --color=auto sleep
itcast@ubuntu:~/classcode/day05$ kill 15451
itcast@ubuntu:~/classcode/day05$ ps -aux | grep sleep
itcast     15470  0.0  0.0   5476   596 pts/0    S+   09:00   0:00 sleep 1000
itcast     15474  0.0  0.0   6432   672 pts/1    S+   09:00   0:00 grep --color=auto sleep
itcast@ubuntu:~/classcode/day05$ kill -9 15470
itcast@ubuntu:~/classcode/day05$ ps -aux | grep sleep
itcast     15479  0.0  0.0   5476   592 pts/0    S+   09:00   0:00 sleep 1000
itcast     15481  0.0  0.0   6432   732 pts/1    S+   09:00   0:00 grep --color=auto sleep
itcast@ubuntu:~/classcode/day05$ kill -SIGKILL 15479

例如:杀死sleep进程的三种方法

1. kill 进程号
2. kill -9 进程号
3. kill -SIGKILL 进程号
  1. killall 命令 :杀死指定名称的所有进程
# 终端1
itcast@ubuntu:~/classcode/day05$ sleep 1000 &
[1] 15565
itcast@ubuntu:~/classcode/day05$ sleep 1000 &
[2] 15566
itcast@ubuntu:~/classcode/day05$ sleep 1000 &
[3] 15567

# 终端2
itcast@ubuntu:~/classcode/day05$ ps -aux | grep sleep
itcast     15565  0.0  0.0   5476   592 pts/0    S    09:04   0:00 sleep 1000
itcast     15566  0.0  0.0   5476   528 pts/0    S    09:04   0:00 sleep 1000
itcast     15567  0.0  0.0   5476   596 pts/0    S    09:04   0:00 sleep 1000
itcast     15571  0.0  0.0   6432   736 pts/1    S+   09:04   0:00 grep --color=auto sleep
itcast@ubuntu:~/classcode/day05$ killall sleep
itcast@ubuntu:~/classcode/day05$ ps -aux | grep sleep
itcast     15583  0.0  0.0   6432   724 pts/1    S+   09:04   0:00 grep --color=auto sleep

4.进程号相关函数

  1. getpid 获取当前进程进程号
  2. getppid 获取父进程号
  3. getpgid 获取进程组号

与fork搭配看效果

5.创建进程 fork

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

int main()
{
    pid_t pid = getpid();
    printf("创建进程前:\n");
    printf("pid = %d,ppid = %d,pgid = %d\n",
           getpid(),getppid(),getpgid(pid));

    fork();

    printf("创建进程后:\n");
    printf("pid = %d,ppid = %d,pgid = %d\n",
           getpid(),getppid(),getpgid(pid));

    return 0;
}

得到的结果因为子进程在结束之前父进程已经结束,从而子进程的父进程变为/bin/bash,同时getgpid返回

  1. getpid 获取当前进程进程号
  2. getppid 获取父进程号
  3. getpgid 获取进程组号

与fork搭配看效果

5.创建进程 fork

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

int main()
{
    pid_t pid = getpid();
    printf("创建进程前:\n");
    printf("pid = %d,ppid = %d,pgid = %d\n",
           getpid(),getppid(),getpgid(pid));

    fork();

    printf("创建进程后:\n");
    printf("pid = %d,ppid = %d,pgid = %d\n",
           getpid(),getppid(),getpgid(pid));

    return 0;
}

得到的结果因为子进程在结束之前父进程已经结束,从而子进程的父进程变为/bin/bash,同时getgpid返回

猜你喜欢

转载自blog.csdn.net/qq_41775886/article/details/107432440