什么是程序?什么是进程?区别在哪里?
程序是通过gcc xx.c-o pro,在磁盘中生产的pro文件
进程是程序正在运行
如何查看系统中的程序:使用ps+grep配合使用查看某一个进程
进程标识符
每一个进程都有一个非负整数表示的唯一的ID------pid
pid=0:称为交换进程
pid=1:init进程——系统初始化
我们可以通过getpid函数获取自身的进程标识符,getppid获取父进程的进程标识符
父进程、子进程
由进程A创建了进程B,A叫做父进程,B叫做子进程,简单理解为我们与父亲之间的关系
我们可以通过fork函数创建一个进程,fork成功调用,返回两次
返回值:0,代表当前进程为子进程
返回值:非负数,代表当前进程为父进程
返回值:-1,代表调用失败
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main(){
pid_t pid;
pid=fork();
if(pid>0){
printf("this is father,pid=%d\n",getpid());
}else if(pid==0){
printf("this is child,pid=%d",getpid());
}
return 0;
}
fork创建一个子进程的目的:
1、一个父进程希望可以多一个同样的自己来同时执行不同的代码。最常见的就是父进程等待客户端的服务请求,当请求到达时,父进程调用fork,让子进程来处理这个请求,父进程继续等待下一个请求
2、一个进程要执行一个不同的程序,这边我们常常调用exec函数
创建进程也可以用vfork函数来创建,那它跟fork函数的区别在于:
1、vfork直接使用父进程的存储空间,不拷贝
2、vfork保证子进程先运行,当子进程调用exit退出后,父进程再执行
进程退出
正常退出
- main函数调用return
- 进程调用exit(),标准c库语言
- 进程调用_exit()或者_Exit,属于系统调用(补充:进程最后一个线程返回,最后一个线程调用pthread_exit())
异常退出
- 调用abort
- 当进程收到某些信号,如ctrl+c
- 最后一个线程对取消(cancellation)请求作出响应
如果我们想要实现终止进程能够通知其父进程它是如何终止,可以通过三个终止函数(exit、_exit、_Exit)将其退出状态作为参数传送给函数,那么禁止进程的父进程用wait或者waitpid函数取得终止状态
父进程等待子进程退出,并收集子进程的退出状态,如果子进程退出状态不被收集,会成为僵尸进程
函数作用:如果所有所有子进程都还在运行,则阻塞;如果一个子进程已终止,正等待父进程获取其终止状态,则取得该子进程的终止状态立即返回;如果没有任何子进程,则立即出错返回
status参数:是一个整数型指针,非空:子进程退出状态放在它所指向的地址中;空:不关心退出状态
pid参数:
- pid== -1,代表着等待任何一子进程,
- pid>0,代表等待其进程ID与pid相等的子进程
- pid==0,代表其组ID等于调用进程组ID的任何一子进程
- pid<-1,代表着其组ID等于pid绝对值的任一进程
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
int main(){
pid_t pid;
int cnt;
int status=10;
pid=fork();
if(pid>0)
{
wait(&status);//接收子进程的退出状态
printf("child quit child status=%d\n",WEXITSTATUS(status));
while(1){
printf("this is father print,pid=%d\n",getpid());
printf("cnt=%d\n",cnt);
sleep(1);
}
}else if(pid==0){
while(1){
printf("this is child print,child pid=%d\n",getpid());
sleep(2);
cnt++;
if(cnt==5){ //当子进程运行5次后,退出
exit(3);
}
}
}
return 0;
}
exec族函数
功能:在调用进程内部执行一个可执行文件。
函数参数说明:
path:可执行文件的路径名称
arg:可执行程序所带的参数,第一个参数为可执行文件名字,没有带路径且arg必须以NULL结束
file:如果参数file中包含/,则为路径名,没有就按环境变量,在所指定的目录下搜素可执行文件
举例:通过exel和fork实现文件的拷贝
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdlib.h>
int main() {
pid_t pid;
int data;
while (1) {
printf("input a number:\n");
scanf("%d", &data);
if (data == 1) {
pid = fork();
if (pid > 0) {
wait(NULL);
} else if (pid == 0) {
if(execl("./copy","copy","file","file2",NULL)== -1){ //子进程调用cp.c
perror("run failed");
}
printf("copy successfully\n");
exit(0);
}
} else {
printf("wait\n");
}
}
return 0;
}
//cp.c-文件拷贝
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char **agrv) {
int fd;
int fd2;
int n_read;
int n_write;
int size;
char *buf;
if(argc!=3){
printf("参数个数不对\n");
exit(-1);
}
fd = open(agrv[1], O_RDWR);
if (fd == -1) {
perror("open file fail");
fd = open(agrv[1], O_RDWR | O_CREAT | O_TRUNC, 0600);
if (fd == -1) {
perror("creat file fail");
exit(-1);
}
}
size = lseek(fd, 0, SEEK_END);
buf = (char *)malloc(size);
printf("%d\n", size);
lseek(fd, 0, SEEK_SET);
n_read = read(fd, buf, size);
printf("read %d from file content:%s\n", n_read, buf);
close(fd);
fd2 = open(agrv[2], O_RDWR);
if (fd2 == -1) {
perror("file2 open file");
fd2 = open(agrv[2], O_RDWR | O_CREAT | O_TRUNC, 0600);
if (fd2 == -1) {
perror("creat file2 fail");
exit(-1);
}
}
n_write = write(fd2, buf, size);
memset(buf, '\0', size);
printf("write %d to file2\n", n_write);
close(fd2);
return 0;
}