Unix 环境高级编程

1. 一切皆文件;
2.对于每种资源都有open/read/write/close操作,因为一切皆文件;
3.对于不清楚的参数,可以使用man: man open; man 2 open; man -s2 open;

4. 函数: strerror ferror sysconf

-----------------------------------------------------

read什么时候会返回?

1. EOF或者关闭(对于文件或者socket)

2. 中断(有些系统会在内核中自动重启,此时用户看不到返回)

-----------------------------------------------------
include 文件路径可以使用gcc -v 获取./configure 的prefix

Mac: /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.13.sdk/usr/include/sys/ 

Linux: /usr/include:

-----------------------------------------------------

// unistd.h

STDIN_FILENO 0
STDOUT_FINLENO 1
STDERR_FILENO 2
//fcntl.h->bits/fcntl.h
O_WRONLY             01  

------------------------------------------------------
无缓冲文件操作函数:
open creat lseek read write pread pwrite close

dup dup2 fcntl
------------------------------------------------------

1.1      重定向符号



>               输出重定向到一个文件或设备 覆盖原来的文件


>!              输出重定向到一个文件或设备 强制覆盖原来的文件


>>             输出重定向到一个文件或设备 追加原来的文件


<               输入重定向到一个程序 

1.2标准错误重定向符号



2>             将一个标准错误输出重定向到一个文件或设备 覆盖原来的文件  b-shell


2>>           将一个标准错误输出重定向到一个文件或设备 追加到原来的文件


2>&1         将一个标准错误输出重定向到标准输出 注释:1 可能就是代表 标准输出


>&             将一个标准错误输出重定向到一个文件或设备 覆盖原来的文件  c-shell


|&              将一个标准错误 管道 输送 到另一个命令作为输入


./a.out 5<>temp 1> test 2>&1 | grep hello   # 使用5作为文件描述符对temp进行读写,将标准错误重定向到标准输出,标准输出重定向的文件test,查找标准输出中包含hello的行显示在标准输出;

----------------------------------------------------------
将errno转化为string: strerror/ perror
----------------------------------------------------------
Linux限制:/usr/include/sys/limits.h
sysconf pathconf fpathconf
----------------------------------------------------------
标准IO重置流的定向: fwide freopen
为文件制定缓冲类型 setbuf setvbuf
带缓冲的IO:
单个字符: getc getchar fgetc ungetc putc fputc putchar    ferror feof

单行: gets fgets puts fputs
二进制IO:fread fwrite
定位流:fseek ftell/ fsetpos fgetpos/fseeko ftello /frewind=fseek(0)

格式化IO:printf scanf/fprintf fscanf/sprintf sscanf/snprintf snscanf

fileno: FILE* -> fd

fdopen: fd->FILE*
临时文件:tmpnam tmpfile
--------------------------------------------------------
getpwuid getpwnam
--------------------------------------------------------
进程终止:
return
exit:关闭IO流,执行"终止处理程序",调用_exit/_Exit
_exit/_Exit:立即进入内核
终止处理程序:atexit
size 查看可执行程序各个存储的大小
存储器内存分配: malloc(不进行初始化) calloc(初始化为0) realloc(更改已分配内存的大小)  free
环境表environ 环境变量:getenv/ setenv/ putenv(name=value)
进程限制:getrlimit/ setrlimit
------------------------------------------------------
进程id getpid/getppid/getuid/geteuid/getgid/getegid


fork/vfork fork会使子进程获得父进程的数据空间,堆和栈的副本,但是很多实现并不立即复制,而是使用写时复制。vfork 子进程在调用exec之前会在父进程的空间中运行。vfork保证子进程先运行完成,并且因为没有拷贝,所以子进程的修改会影响父进程。以下代码还有一点要注意,调用的退出是_exit而不是exit。如果使用exit,行为取决于标准i/o的实现,如果exit只是冲洗缓冲,则和_exit没有区别,但是如果除了冲洗缓冲,还关闭标准i/o,则后面的printf不会有输出,因为子进程借用了父进程的stdout这个标准输出文件对象FILE*,如果关闭,父进程的printf会返回-1,不会有任何输出。但是此时的fileno, STDOUT_FILENO仍然可用,即使再子进程中关闭了。以上分析仅仅限于vfork的情况,对于fork,父子进程中FILE*和fileno都是独立的,使用exit和_exit没有区别(写时复制)。

int main(int argc, char **argv) {
    int a = 5;
    int b = 9;
    pid_t pid = vfork();
    if (pid == 0) {
        //a++;
        b++;      //vfork子进程中的修改会影响到父进程
        sleep(4); //即使是sleep,父进程会一直等待其处理完成再运行
        _exit(0); //必须显式调用_exit,否则父进程打印出来的数值是乱码,即使子进程什么都不做
    } else {
        printf("parent: %d, a: %d, b: %d\n", getpid(), a, b); //parent: 40897, a: 5, b: 10
    }
}


如果父进程先终止,则子进程变成init进程的子进程。

父子进程通信:

wait等待任意结束的子进程,返回值是子进程id,其参数返回的是进程的退出状态,可以通过WIFEXITED,WIFSIGNALED等宏判断退出类型;

waitpid可以等待任意子进程或者指定的进程,进程组进程等;

waitid 类似于waitpid,但是通过标志位,而不是pid字段的正、负、零等区分含义。

wait3 wait4会返回进程退出后的资源统计,包括用户CPU时间,系统CPU时间,页面出错次数,信号次数等。

------------------------------------------------------

exec系列函数

p表示使用filename作为参数,在PATH中寻找可执行文件;

l表示需要参数列表,v表示参数vector数组,l v 互斥;

e表示使用envp[]数组作为环境变量,而不是使用系统环境变量;

exec在原有的进程中执行新的程序,继承了进程各种id等信息。文件描述符是否关闭和原进程中打开文件描述符时的FD_CLOEXEC标志位有关;exec执行前后实际用户id和组id不变,但是有效用户id和组id取决于执行程序文件的有效用户id和组id的配置。

exec函数执行之后,进程开始执行新的程序,exec之后的代码不会被执行,除非出错。所以一般exec函数会在子进程中执行。执行exec之后,文件描述符是否仍旧打开,取决于close-exec(FD_CLOEXEC)标志位,默认是打开的。

int main() {
    char *cmd[] = {"ls", "-al", "/", 0};
    char *cmd2[] = {"env", 0};
    char *env_list[] = {"PATH=/987"};
    int err;
    //err = execlp("ls", "ls", "../", (char *) 0);
    //err = execvp("ls", cmd);
    //err = execl("/bin/ls", "ls", "../", (char *) 0);
    //err = execv("/bin/ls", cmd);
    //err = execle("/usr/bin/ls", "env", 0, env_list);
    // system call
    err = execve("/usr/bin/env", cmd2, env_list);

    printf("err msg: %s\n", strerror(err));
}

------------------------------------------------------

注册信号处理函数:signal

发送信号:kill/raise/alarm

------------------------------------------------------

线程:pthread_equal

pthread_self----getpid

pthread_create----fork/vfork

pthread_exit----exit

pthread_join----waitpid,后面可以传入value_ptr参数,这个是线程的返回值。类型是void**是因为线程的返回值是 void*

pthread_cancel_push----atexit

pthread_cancel----abort

pthread_detach detach之后,线程无法再被join;相对于进程的SIGCHLD信号为SIGIGN,线程的终止状态自动被释放。

pthread_mutex_init/pthread_mutex_destroy/pthread_mutex_lock/pthread_mutex_unlock/pthread_mutex_trylock

pthread_rwlock_init/pthread_rwlock_destroy/pthread_rwlock_rdlock/pthread_rwlock_wrlock/pthread_rwlock_unlock

pthread_cond_init/pthread_cond_destroy/pthread_cond_wait/pthread_cond_timedwait

------------------------------------------------------

进程通信:signal/pipe(int fd[2])/getmsg/getsem/mkfifo

=============================================================================================

1. read/write不带缓冲,标准i/o带缓冲。如果标准i/o连接到终端,则是行缓冲的,否则是全缓冲的。

2. 使用fork创建进程:重定向父进程的标准输出时,子进程的标准输出也被重定向;父进程打开的所有的文件描述符都被复制到子进程中,父子进程的每个相同的打开的文件描述符共享同一个文件表项。如果一个进程有标准输入、标准输出和标准错误,在fork返回时如下:

使用fork创建的父子进程的区别:进程的id和父进程id不同,文件锁不会被继承,子进程未处理的闹钟被清除,未处理的信号集被清空。使用fork失败的主要原因有系统中创建了太多进程。


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值