printf 函数输出问题
printf 函数并不会直接将数据输出到屏幕,而是先放到缓冲区中,只有一下三种情况满足,才会输出到屏幕。
- 缓冲区满
- 强制刷新缓冲区 fflush
- 程序结束时
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char* argv[],char* envp[])
{
printf("hello");
//fflush(stdout);
sleep(3);
exit(0);
}
主函数参数介绍
int main( int argc, char* argv[], char* envp[])
- argc 参数个数
- argv 参数内容
- envp 环境变量
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>
//参数个数 参数内容 环境变量
int main(int argc, char* argv[],char* envp[])
{
int i = 0;
printf("argc=%d\n",argc);
for( ;i < argc; i++ )
{
printf("argv[%d]=%s\n",i,argv[i]);
}
for( i = 0; envp[i] != NULL; i++ )
{
printf("envp[%d]=%s\n",i,envp[i]);
}
exit(0);
}
代码执行结果:
复制进程 fork
fork 方法
pid_t fork(void);
函数返回类型 pid_t 实质是 int 类型,Linux 内核 2.4.0 版本的定义是
fork 函数会新生成一个进程,调用 fork 函数的进程为父进程,新生成的进程为子进程。在父进程中返回子进程的 pid,在子进程中返回 0,失败返回-1。
僵死进程及处理方法
- 僵死进程概念:子进程先于父进程结束,父进程没有调用 wait 获取子进程退出码。
- 如何处理僵死进程:父进程通过调用 wait()完成。
- Init 进程收养孤儿进程
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>
int main(int argc, char* argv[],char* envp[])
{
char * s = NULL;
int n = 0;
pid_t pid = fork();
assert( pid != -1 );
if ( pid == 0 )
{
s = "child";
n = 4;
}
else
{
s = "parent";
n = 10;
}
int i = 0;
for(; i < n; i++ )
{
printf("pid=%d,s=%s\n",getpid(),s);
sleep(1);
}
exit(0);
}
运行结果如下图:
从上图中可以看到,当子进程结束后,并没有消失,仍然可以在系统中观测到,但此时子进程其实已经运行结束了,此时子进程的状态被称为僵死状态,系统把处于该类状态的进程称为僵死进程 (defunct)。如果父进程先结束,子进程最后是不会变为僵死进程的(孤儿进程,被1号进程收养)。
操作文件的系统调用
- 文件操作有关的系统调用
int open(const char* pathname, int flags);//用于打开一个已存在的文件
int open(const char* pathname, int flags,mode_t mode);//用于新建一个文件,并设置访问权限
参数介绍:
pathname:将要打开的文件路径和名称
flags : 打开标志,如 O_WRONLY 只写打开
O_RDONLY 只读打开
O_RDWR 读写方式打开
O_CREAT 文件不存在则创建
O_APPEND 文件末尾追加
O_TRUNC 清空文件,重新写入
mode: 权限 如:“0600”
返回值:为文件描述符
ssize_t read(int fd, void* buf, size_t count);
参数介绍:
fd 对应打开的文件描述符
buf 存放数据的空间
count 计划一次从文件中读多少字节数据
返回值:为实际读到的字节数
ssize_t write(int fd, const void* buf,size_t count);
参数介绍:
fd 对应打开的文件描述符
buf 存放待写入的数据
count 计划一次向文件中写多少数据
int close(int fd);
参数介绍:
fd 要关闭的文件描述符
由于 fork 创建的子进程的 PCB 是拷贝父进程的,子进程的 PCB 中的文件表指向打开文件的指针只是拷贝了父进程 PCB 中的值,所以父子进程会共享父进程 fork 之前打开的所有文件描述符。
系统调用与库函数的区别
系统调用的实现在内核中,属于内核空间,库函数的实现在函数库中,属于用户空间。
进程替换
exec 系列替换过程:pcb 使用以前的只修改,进程实体更换。注意该系列方法功能都一样,没有区别,只是参数不同。