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失败的主要原因有系统中创建了太多进程。