如何在后台运行的 c++ 中编写 cp 函数(在 linux shell 中)?
how to write a cp function (in linux shell ) in c++ that runs in background?
我正在尝试写一个自己的小linux shell,我想写函数cp
,函数格式如下:
cp <old-file-path> <new-file-path>
它将第一个文件复制到第二个文件(覆盖它),如果第二个文件不存在,它将创建一个新文件。
如果文件没有打开或任何系统调用没有成功,它将打印一条错误消息。
但是,有时我想复制大文件,所以我想在后台 运行 这个 cp
命令(使用 fork
而不等待它完成)。
我的问题是:如何使用 fork
而不等待进程完成?
目前,子进程变成了僵尸进程。
这是我的代码:
// num_args contains the number of arguments sent to cp
class CopyCommand : public BuiltInCommand {
public:
CopyCommand(const char* cmd_line) : BuiltInCommand(cmd_line){}
virtual ~CopyCommand() {}
void execute() override{
if(this->num_args < 1){ // if no arguments were send to cp
perror("invalid arguments");
return;
}
char* buff;
int fd1 = open(args[1], O_RDONLY);
if(fd1 == -1){
perror("open failed");
return;
}
if(this->num_args==2){ // copy file1 into file2 (overrite file 1)
int fd2 = open(args[2], O_TRUNC);
if (fd2 == -1) { // if we couldn't open the file then create a new one (not sure if we supposed to this ?)
fd2 = open(args[2], O_CREAT, 0666);
if (fd2 == -1) {
perror("open failed");
return;
}
}
pid_t PID = fork();
if(PID == -1){
perror("fork failed");
return;
}
else if(PID == 0){
// i need to use fork here :( before i start to write
int read_res = read(fd1, &buff, 1); /// read from the file fd1 into fd2
while (read_res != -1) {
if (!read_res) {
break;
}
if (write(fd2, buff, 1) == -1) {
perror("write failed");
}
read_res = read(fd1, buff, 1);
}
if (read_res == -1) {
perror("read failed");
}
}
}
else if(this->num_args==1){ // create file2 and copy file1 into file2
// don't know how to do this yet
// i need to use fork here :(
}
}
};
首先,我稍微重写了您的代码。
特别要注意,子分支 (PID == 0) 在完成后退出。
父级在分叉后关闭传递的文件描述符,以防出现错误。
if (this->num_args == 2) {
int fd1 = open(args[1], O_RDONLY);
if (fd1 == -1) {
perror("open failed");
return;
}
int fd2 = open(args[2], O_TRUNC);
if (fd2 == -1) {
fd2 = open(args[2], O_CREAT, 0666);
if (fd2 == -1) {
perror("open failed");
close(fd1);
return;
}
}
pid_t PID = fork();
if (PID == -1) {
perror("fork failed");
} else if (PID == 0) {
char buff[1024];
int read_res = read(fd1, &buff, 1024); /// read from the file fd1 into fd2
while (read_res != -1) {
if (!read_res) {
break;
}
if (write(fd2, buff, read_res) == -1) {
perror("write failed");
}
read_res = read(fd1, buff, 1024);
}
if (read_res == -1) {
perror("read failed");
}
exit(0);
} else {
printf("Copy running in background (pid: %d)\n", PID);
}
close(fd1);
close(fd2);
return
}
当子进程调用exit
时,进程会停留在"Zombie"状态。此状态允许父进程(您)调用 wait
或 waitpid
来检索退出代码。
作为进程结束的次要影响,内核将向您的进程发送一个 SIGCHLD
,让您知道您实际上可以调用 wait
而不会阻塞。在你的情况下,你不关心退出代码,所以你可以在程序开始时设置一个 "don't care" 信号处理程序,让内核清理进程:
signal(SIGCHLD, SIG_IGN);
这在 signal(2) 中有记录:
If a process explicitly specifies SIG_IGN as the action for the signal
SIGCHLD, the system will not create zombie processes when children of the
calling process exit. As a consequence, the system will discard the exit
status from the child processes.
我正在尝试写一个自己的小linux shell,我想写函数cp
,函数格式如下:
cp <old-file-path> <new-file-path>
它将第一个文件复制到第二个文件(覆盖它),如果第二个文件不存在,它将创建一个新文件。
如果文件没有打开或任何系统调用没有成功,它将打印一条错误消息。
但是,有时我想复制大文件,所以我想在后台 运行 这个 cp
命令(使用 fork
而不等待它完成)。
我的问题是:如何使用 fork
而不等待进程完成?
目前,子进程变成了僵尸进程。
这是我的代码:
// num_args contains the number of arguments sent to cp
class CopyCommand : public BuiltInCommand {
public:
CopyCommand(const char* cmd_line) : BuiltInCommand(cmd_line){}
virtual ~CopyCommand() {}
void execute() override{
if(this->num_args < 1){ // if no arguments were send to cp
perror("invalid arguments");
return;
}
char* buff;
int fd1 = open(args[1], O_RDONLY);
if(fd1 == -1){
perror("open failed");
return;
}
if(this->num_args==2){ // copy file1 into file2 (overrite file 1)
int fd2 = open(args[2], O_TRUNC);
if (fd2 == -1) { // if we couldn't open the file then create a new one (not sure if we supposed to this ?)
fd2 = open(args[2], O_CREAT, 0666);
if (fd2 == -1) {
perror("open failed");
return;
}
}
pid_t PID = fork();
if(PID == -1){
perror("fork failed");
return;
}
else if(PID == 0){
// i need to use fork here :( before i start to write
int read_res = read(fd1, &buff, 1); /// read from the file fd1 into fd2
while (read_res != -1) {
if (!read_res) {
break;
}
if (write(fd2, buff, 1) == -1) {
perror("write failed");
}
read_res = read(fd1, buff, 1);
}
if (read_res == -1) {
perror("read failed");
}
}
}
else if(this->num_args==1){ // create file2 and copy file1 into file2
// don't know how to do this yet
// i need to use fork here :(
}
}
};
首先,我稍微重写了您的代码。 特别要注意,子分支 (PID == 0) 在完成后退出。 父级在分叉后关闭传递的文件描述符,以防出现错误。
if (this->num_args == 2) {
int fd1 = open(args[1], O_RDONLY);
if (fd1 == -1) {
perror("open failed");
return;
}
int fd2 = open(args[2], O_TRUNC);
if (fd2 == -1) {
fd2 = open(args[2], O_CREAT, 0666);
if (fd2 == -1) {
perror("open failed");
close(fd1);
return;
}
}
pid_t PID = fork();
if (PID == -1) {
perror("fork failed");
} else if (PID == 0) {
char buff[1024];
int read_res = read(fd1, &buff, 1024); /// read from the file fd1 into fd2
while (read_res != -1) {
if (!read_res) {
break;
}
if (write(fd2, buff, read_res) == -1) {
perror("write failed");
}
read_res = read(fd1, buff, 1024);
}
if (read_res == -1) {
perror("read failed");
}
exit(0);
} else {
printf("Copy running in background (pid: %d)\n", PID);
}
close(fd1);
close(fd2);
return
}
当子进程调用exit
时,进程会停留在"Zombie"状态。此状态允许父进程(您)调用 wait
或 waitpid
来检索退出代码。
作为进程结束的次要影响,内核将向您的进程发送一个 SIGCHLD
,让您知道您实际上可以调用 wait
而不会阻塞。在你的情况下,你不关心退出代码,所以你可以在程序开始时设置一个 "don't care" 信号处理程序,让内核清理进程:
signal(SIGCHLD, SIG_IGN);
这在 signal(2) 中有记录:
If a process explicitly specifies SIG_IGN as the action for the signal SIGCHLD, the system will not create zombie processes when children of the calling process exit. As a consequence, the system will discard the exit status from the child processes.