一、文件
API:open()、read()、write()、close()、lseek()
//int open(const char *pathname, int flags);
//return:成功打开或创建返回int型文件描述符,错误打开或创建返回-1.
open("./pathname",O_CREAT|O_RDWR,0666);
open("./pathname",O_RDWR);
//ssize_t read(int fd, void *buf, size_t count);
//ssize_t write(int fd, const void *buf, size_t count);
//return:On success, the number of bytes read is returned.On error, -1 is returned.
//int close(int fd);
//off_t lseek(int fd, off_t offset, int whence);
//参数1.fd:操作文件fd 2.offset:一般为0 3.whence:SEEK_SET SEEK_END
int size = lseek(fd,0,SEEK_END);
//光标在文件中从0(开头)到END移动的次数size(文件大小),光标在文件最后
lseek(fd,0,SEEK_SET);
//光标在文件的开头
二、进程
程序是静态的概念,进程是动态的概念。
查看进程状态:1.ps(当前系统进程状态) 2.top(实时显示系统各个进程资源占用情况)
ps指令:
a.ps -aux 显示进程
b.ps -aux xxx 显示含xxx的进程
c.ps aux | grep xxx //查到使用xxx的进程
top指令:top [-d number] | top [-bnp]
进程标识符:每一个进程都有一个非负整数表示的唯一ID,叫做PID。getpid()函数获取自身的进程标识符;getppid()函数获取父进程的进程标识符。
c内存存储空间分配:
数据段:存放初始化后的变量
bss:存放未初始化的变量
堆:malloc中申请的空间在堆中
栈:函数调用,函数调用的局部变量和返回值的存放。
父子进程
pid_t fork(void);//创建子进程
父子进程:A创建B,A为父进程,B为子进程
调用成功返回两次: 返回为0 为子进程;返回为非负 为父进程
调用失败返回-1
int main()
{
int data;
pid_t pid;
while(1){
printf("Please scanf a data:\n");
scanf("%d",&data);
if(data==1){
pid=fork();
if(pid>0){
wait(NULL);
}
if(pid==0){
//execl("./changdata","changdata","congfig.txt",NULL);
system("./changdata congfig.txt");
exit(0);
}
}else{
printf("that nothing!\n");
}
}
return 0;
}
vfork():直接使用父进程的存储空间不进行拷贝;保证子进程先运行,调用exit函数退出后,父进程才执行。
进程退出:
a正常退出:1.main调用return 2.进程调用exit() 标准c库 3.进程调用_exit()、_Exit() 系统调用 (补充:进程最后一个线程返回;最后一个线程调用pthread_exit)
b异常退出:1.调用abort 2.Ctrl+c 3.最后一个线程对取消请求做出响应
孤儿进程:父进程不等待子进程退出,在子进程之前就结束了自己的“生命”,此时子进程叫做孤儿进程。
父进程等待子进程退出用exit() 正常退出用WEXITSTATUS()刷新。
exec族函数
execl、execlp、execle、exexv、execvp、execupe
功能:调用进程内部执行一个可执行文件。可执行文件可以是内部的二进制文件也可以是linux下可执行脚本文件。
#include <unistd.h>
extern char **environ;
int execl(const char *path, const char *arg, ...);
int execlp(const char *file, const char *arg, ...);
int execle(const char *path, const char *arg,..., char * const envp[]);
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
int execvpe(const char *file, char *const argv[],char *const envp[]);
exec族函数参数极难记忆和分辨,函数名中的字符会给我们一些帮助:
l : 使用参数列表
p:使用文件名,并从PATH环境进行寻找可执行文件
v:应先构造一个指向各参数的指针数组,然后将该数组的地址作为这些函数的参数。
e:多了envp[]数组,使用新的环境变量代替调用进程的环境变量
参考exec族函数链接:
(80条消息) linux进程---exec族函数(execl, execlp, execle, execv, execvp, execvpe)_云英的博客-CSDN博客_execvpe
echo $PETH :打印环境变量 export PATH= PATH:路径 添加环境变量
//int system(const char *command);
//FILE *popen(const char *command, const char *type);
//int pclose(FILE *stream);
//size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
//popen()配合fread()进行使用最后pclose()
//popen 可以获取输出结果
/*总的来说,请求popen调用运行一个程序时,它首先启动shell,即系统的shell命令,然后将command字符串作为一个参数传递给它。这样就有了优缺点:
优点是:由于所有类Unix系统中参数扩展都是由shell完成的,所有它运行我们通过popen完成非常复杂的shell命令。而其他一些创建进程的函数(如execl)调用起来就复杂的多,因为调用进程必须自己完成shell扩展。
缺点是:针对每个popen调用,不仅要启动一个被请求的程序,还要启动一个shell,即每个popen调用将启动两个进程。从节省系统资源的角度来看,popen函数的调用成本略高,并且对目标命令的调用比正常方式慢一些(通过pipe改进)。
和system相比,system就是执行shell命令最后返回是否执行成功,popen执行命令并且通过管道和shell命令进行通信。*/
僵尸进程:原因进程没有释放