<unix高级编程>笔记 chapter1

os严格上是软件,为计算机提供资源和app运行环境. 特称为内核.

内核的接口被成为system call;然后库函数对system call进行了封装;shell是特殊app,为运行其他程序提供了一个接口.

shell是个命令行解释器,读取输入,执行命令.

unix文件系统是由directory和file组成.目录起点成为root,名字是/.

文件属性指类型\大小\所有者\权限以及修改时间.stat和fstat返回文件属性的结构.

比如下面操作:




2.文件名

只有/和null不能出现在文件名里.因为/用来分割构成路径名,null用来终止一个路径名.

创建新目录的适合会自动创建两个文件名.和..

点指当前目录,..指上一级目录.


3.路径名

一个或者多个/构成路径名.

以/开头指相对路径,否则是绝对路径. 其实经常用的是相对路径.


实战:

1.列出目录下的所有文件.就是实现ls功能.

#include <dirent.h>
#include "stdio.h"
#include "stdlib.h"


int main(int argc, char** argv){
    if (argc != 2){
        printf("usage: ls dir_name\n");
        return 1;
    }

    DIR* dp = opendir(argv[1]);
    if (NULL == dp){
        printf("can't open %s\n", argv[1]);
        return 1;
    }

    printf("load dir success\n");

    struct dirent* dirp = NULL;
    while ((dirp = readdir(dp)) != NULL)
        printf("%s ", dirp->d_name);

    printf("\n");
    closedir(dp);

    return 0;
}

从结果看出来 . 和.. 的确是有效目录.打印结果是无序的.而ls结果是有序的.

exit(0)标示程序正常退出.1-255表示错误码.


1.5 输入和输出


fd是个非负整数.是内核用来标示特定进程正在访问的文件.

每当shell被打开,都有三个默认fd被打开:stdin stdout stderror

另外shell可以方便地重定向.

3)不用缓冲的IO

open read close write lseek 提供了不用缓冲的IO

代码:

#include "stdio.h"
#include "unistd.h"

int main(){
    int n = 0;
    const int maxLen = 4096;
    char buff[maxLen];

    while ((n == read(STDIN_FILENO, buff, maxLen)) > 0){
        if (write(STDOUT_FILENO, buff, n) != n){
            printf("error\n");
            exit(1);
        }
    }
    
    exit(0);
}

1.6 程序和进程

程序是存放在磁盘上,处于某个目录的一个可执行文件.

程序的执行实例叫做进程.

每个进程都有一个唯一ID,被称为进程ID.可用getpid打印.关于这个函数可以man下,手册讲的很详细,比如 pid常用于产生唯一文件名,在glibc里被封装后缓存,所以这个函数不是系统调用,不用担心开销.

其实在shell下ps命令就可以获取当前进程的ID.



进程控制的主要函数是 fork,exec,waitpid.

同一进程内线程共享地址空间,fd,栈,以及进程相关的属性.


1.7 出错处理

常常返回errno,而且是个左值,在linux下是线程安全的.

错误分为致命性错误和非致命性错误.

1.8用户标示

用户ID为0的用户未超级用户,对系统有自由的支配权.

还有组ID 可以分别用getuid和getgid获取.

1.9 信号

signal是通知进程已经发生某种情况的技术.

比如除数为0 将引发sigfpe信号,

进程可以选择:

1)忽略

2)默认方式:比如sigfpe就是默认终止进程

3)提供一个函数,捕捉该信号.

终端键盘上有两种产生信号的方法: 中断键:Delete或Ctrl+C;退出键;当然kill能杀死进程,在shell里就可以.

下面展示如何响应"中断进程(ctrl+c)"这个信号:

#include "stdio.h"
#include "unistd.h"
#include "sys/wait.h"

static void sig_int(int signo){
    printf("interrupt\n");
}


int main(){
    const int MAXLINE = 1024;
    char buf[MAXLINE];
    pid_t pid;
    int status = 0;

    if (signal(SIGINT, sig_int) == SIG_ERR){
        printf("sigal error\n");
        exit(1);
    }
    while (fgets(buf, MAXLINE, stdin) != NULL){
        if (buf[strlen(buf)-1] == '\n')
            buf[strlen(buf)-1] = 0;

        if ((pid = fork()) < 0){
            printf("fork error\n");
            return 0;
        }

        if (pid == 0){
            execlp(buf, buf, (char*)0);
            printf("cant't execute:%s\n", buf);
            exit(127);
        }


        if ((pid == waitpid(pid, &status, 0)) < 0){
            printf("waitpid error\n");
            exit(1);
        }

        printf("%%%");
    }

    exit(0);
}

这样就捕捉了.

然后可以看看kill如何杀死某进程:


1.10 时间值

unix一直使用两种时间:

1)日历时间.即UTC时间,用time_t标示;

2)进程时间,也被成为cpu时间,以度量进程使用的cpu资源.进程时间以tick计算,每秒取50,60或者100个tick.用clock_t保存.

unix采用三种方式度量进程执行时间:

1)时钟时间. 是进程运行的时间总量.

2)user CPU时间. 执行用户命令所用时间,

3)系统cpu时间. 指执行内核程序经历时间.

shell下time(1)即可取得上述三种时间:


1.11 syscall和库函数

unix提供定义明确,数量有限,可直接进入内核的入口点 被称为系统调用.

linux提供240-260个系统调用.

用户函数可以调用库函数,然后产生软终端进入内核的机器指令.

当然有的库函数不执行任何系统调用,比如strcpy和atoi

以malloc为例,它使用sbrk系统调用,按指定字节增加或减少进程地址空间.

malloc在用户层次管理空间;sbrk在内核层管理.


另外系统调用提供最小接口;库函数功能较复杂.


至于课后题.

1.1 前面已经验证,属于不同目录

1.2表明每次运行改程序,都产生了一个新进程.

1.3perror的参数只是给用户来加额外说明,不能被改变;strerror传入int 因为是传值,与原参数无关系,不需要const;


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值