linux学习:进程

目录

例子1    获取当前进程的进程标识符

例子2   创建一个新的子进程

例子3    展示了父进程和子进程的进程标识符

例子4     区分父进程和子进程

例子5     区分父进程和子进程的行为

例子6    比较进程标识符来区分父进程和子进程

例子7     子进程如何修改一个变量,对父进程的影响

例子8     子进程创建并循环执行,每隔3秒打印一条消息

例子9    父进程和子进程分别进入循环,每隔一秒打印一条消息

例子10     vfork()创建子进程

例子11    vfork() 创建子进程,执行一定次数后会自行退出

例子12    

例子13    创建子进程,父子不同的操作。子在一定条件下会自行退出

例子14    父等待子进程结束后继续执行

例子15    wait() 父等待子结束,父打印子进程的退出状态

例子16   waitpid替代 wait检查子状态,waitpid允许父进程进行非阻塞检查或等待特定的子进程结束

例子17   子在一定条件下会自行退出,而父进程仅打印一次信息

例子18   execl执行一个新的程序。这个函数属于 exec 系列函数,它们用于替换当前进程的映像

例子19    execl函数来执行 /bin/ls 命令,通常用于列出目录内容。如果 execl() 调用成功,则不会返回;如果调用失败,会返回 -1 并打印错误信息

例子20    execl函数来执行 /bin/ls 命令,配上 -l 选项来以长格式列出目录内容。如果 execl() 调用成功,则会替换当前进程的映像并不返回;如果失败,会返回 -1 并打印错误信息

例子21    execl()执行系统命令 /bin/date,该命令用于显示当前系统日期和时间。如果 execl()调用成功,它会替换当前进程的映像为 /bin/date 并不返回;如果失败,会返回 -1 并打印错误信息

例子22    execlp()执行系统命令 ps,该命令用于显示当前系统的进程状态。如果 execlp() 调用成功,它会替换当前进程的映像为 ps 命令并不返回;如果失败,会返回 -1 并打印错误信息

例子23    execvp()执行系统命令 ps,用于显示当前系统的进程状态。execvp() 类似于 execlp(),但允许通过一个参数数组来传递命令和其参数。如果 execvp() 调用成功,它会替换当前进程的映像为 ps 命令并不返回;如果失败,会返回 -1 并打印错误信息

例子24    execv()执行 /bin/ps 命令,该命令用于显示当前系统的进程状态。execv() 类似于 execl(),但使用数组来传递命令和其参数。如果 execv() 调用成功,它会替换当前进程的映像为 /bin/ps 并不返回;如果失败,会返回 -1 并打印错误信息

例子25  输入来触发文件操作,在子进程中进行。这个例子特别是在输入为 1 时,程序会修改配置文件 config.txt 中的一个特定值

例子26    根据输入决定是否创建一个子进程来执行特定的程序 (changData),该程序预期对 config.txt 文件进行修改。如果输入不是 1,则打印消息并继续等待

例子27    根据输入决定执行一个外部命令(changData),该命令与配置文件 config.txt 相关联。如果用户输入 1,程序会创建一个子进程,该子进程通过 system 函数调用外部程序 ./changData 来处理文件 config.txt

例子28    system() 执行系统命令(在本例中是 ps),这个命令用来列出当前运行的进程。然而,该代码示例存在一个问题:它没有捕获 system() 调用的输出

例子29   popen() 和 fread() 函数从 ps 命令获取输出并将其读入到一个字符数组中。该程序展示了如何执行系统命令并捕获其输出,适合需要从命令行工具中直接读取数据的场景

例子30   处理命令行参数。它通过遍历 argc 和 argv 数组来打印所有传递给程序的参数

例子31   等待用户输入。当用户输入 1 时,程序会创建一个子进程,这个子进程会修改一个文件(./file1)中特定字符串("LENG=")之后的字符

例子32    execl()函数是为了替换当前的进程映像为/bin/ls命令的进程映像

例子33   vfork()创建子进程并控制执行顺序


例子1    获取当前进程的进程标识符

#include <stdio.h>   // 引入标准输入输出库,用于打印
#include <sys/types.h> // 引入数据类型,包括 pid_t
#include <unistd.h>    // 引入 POSIX 操作系统API,包括 getpid()int main()
{pid_t pid;  // 定义进程标识符变量pid = getpid(); // 调用getpid()函数获取当前进程的PIDprintf("my pid is %d\n", pid);  // 打印当前进程的PIDwhile(1);  // 使程序进入无限循环,防止程序立即结束return 0;  // 正常情况下,程序不会执行到这里,因为上面有无限循环
}

例子2   创建一个新的子进程

#include <stdio.h>   // 引入标准输入输出库,用于打印
#include <sys/types.h> // 引入数据类型,包括 pid_t
#include <unistd.h>    // 引入 POSIX 操作系统API,包括 getpid() 和 fork()int main()
{pid_t pid;  // 定义进程标识符变量pid = getpid(); // 调用getpid()函数获取当前进程的PIDfork(); // 调用fork()创建一个子进程。父进程中,fork返回新创建的子进程的PID;在子进程中,fork返回0。printf("my pid is %d\n", pid);  // 打印当前进程的PID,注意这里将在父进程和子进程中都执行。return 0;  // 结束程序,父进程和子进程都会到达这里并退出
}

例子3    展示了父进程和子进程的进程标识符

#include <stdio.h>   // 引入标准输入输出库,用于打印
#include <sys/types.h> // 引入数据类型,包括 pid_t
#include <unistd.h>    // 引入 POSIX 操作系统API,包括 getpid() 和 fork()int main()
{pid_t pid;  // 定义进程标识符变量pid = getpid(); // 调用getpid()函数获取当前进程的PIDfork(); // 调用fork()创建一个子进程。父进程中,fork返回新创建的子进程的PID;在子进程中,fork返回0。// 在printf中显示初始进程的PID和当前进程的PID。// "pid" 是调用fork()之前的父进程的PID。// "getpid()" 将获取当前进程的PID,这在父进程和子进程中可能不同。printf("my pid is %d, current pro id:%d\n", pid, getpid());return 0;  // 结束程序,父进程和子进程都会到达这里并退出
}

例子4     区分父进程和子进程

#include <stdio.h>   // 引入标准输入输出库,用于打印
#include <sys/types.h> // 引入数据类型,包括 pid_t
#include <unistd.h>    // 引入 POSIX 操作系统API,包括 getpid() 和 fork()int main()
{pid_t pid;  // 定义一个pid_t类型变量来存储原始进程的PIDpid_t pid2; // 定义另一个pid_t类型变量来存储fork后的进程PIDpid = getpid(); // 获取并存储当前进程的PIDprintf("before fork: pid = %d\n", pid); // 打印fork前的PIDfork(); // 创建一个新的子进程。父进程中,fork返回子进程的PID;子进程中,fork返回0。pid2 = getpid(); // 获取fork后当前进程的PIDprintf("after fork: pid = %d\n", pid2); // 打印fork后的PIDif(pid == pid2){// 如果fork前后的PID相同,说明代码在父进程中执行printf("this is father print\n");}else{// 如果fork前后的PID不同,说明代码在子进程中执行printf("this is child print, child pid = %d\n", getpid());}return 0;  // 程序结束,父子进程都将执行到此处并退出
}

例子5     区分父进程和子进程的行为

#include <stdio.h>   // 引入标准输入输出库,用于打印
#include <sys/types.h> // 引入数据类型,包括 pid_t
#include <unistd.h>    // 引入 POSIX 操作系统API,包括 getpid() 和 fork()int main()
{pid_t pid; // 定义一个pid_t类型变量来存储fork()的返回值// 打印当前进程的PID,此时为父进程printf("father: id=%d\n", getpid());pid = fork(); // 调用fork()来创建一个新的子进程if (pid > 0){// 如果pid大于0,说明是父进程执行的代码块// 在父进程中,fork()返回创建的子进程的PIDprintf("this is father print, pid = %d\n", getpid());}else if (pid == 0){// 如果pid等于0,说明是子进程执行的代码块// 在子进程中,fork()返回0printf("this is child print, child pid = %d\n", getpid());}// 两个进程都将执行到这里,并结束程序return 0;
}

例子6    比较进程标识符来区分父进程和子进程

#include <stdio.h>   // 引入标准输入输出库,用于打印
#include <sys/types.h> // 引入数据类型,包括 pid_t
#include <unistd.h>    // 引入 POSIX 操作系统API,包括 getpid() 和 fork()int main()
{pid_t pid;     // 定义一个pid_t类型变量来存储原始进程的PIDpid_t pid2;    // 定义另一个pid_t类型变量来存储fork后的进程PIDpid_t retpid;  // 定义一个pid_t类型变量来存储fork()的返回值pid = getpid(); // 获取并存储当前进程的PIDprintf("before fork: pid = %d\n", pid); // 打印fork前的PIDretpid = fork(); // 创建一个新的子进程。父进程中,fork返回子进程的PID;在子进程中,fork返回0。pid2 = getpid(); // 获取fork后当前进程的PIDprintf("after fork: pid = %d\n", pid2); // 打印fork后的PIDif(pid == pid2){// 如果fork前后的PID相同,说明代码在父进程中执行// retpid将是子进程的PID,因为在父进程中,fork()返回子进程的PIDprintf("this is father print: iretpid = %d\n", retpid);}else{// 如果fork前后的PID不同,说明代码在子进程中执行// 在子进程中,fork()返回0printf("this is child print, retpid=%d, child pid = %d\n", retpid, getpid());}return 0;  // 程序结束,父子进程都将执行到此处并退出
}

例子7     子进程如何修改一个变量,对父进程的影响

#include <stdio.h>   // 引入标准输入输出库,用于打印
#include <sys/types.h> // 引入数据类型,包括 pid_t
#include <unistd.h>    // 引入 POSIX 操作系统API,包括 getpid() 和 fork()int main()
{pid_t pid; // 定义一个pid_t类型变量来存储fork()的返回值int data = 10; // 定义一个整型变量data,并初始化为10// 打印当前进程的PID,此时为父进程printf("father: id=%d\n", getpid());pid = fork(); // 调用fork()来创建一个新的子进程if (pid > 0){// 如果pid大于0,说明是父进程执行的代码块// 在父进程中,fork()返回创建的子进程的PIDprintf("this is father print, pid = %d\n", getpid());}else if (pid == 0){// 如果pid等于0,说明是子进程执行的代码块// 在子进程中,fork()返回0printf("this is child print, child pid = %d\n", getpid());// 子进程中修改data变量data = data + 100; // 将data加100}// 在父进程和子进程中都将执行到这里,并打印data的值printf("data=%d\n", data);return 0; // 程序结束,父子进程都将执行到此处并退出
}

例子8     子进程创建并循环执行,每隔3秒打印一条消息

#include <stdio.h>   // 引入标准输入输出库,用于打印和输入
#include <sys/types.h> // 引入数据类型,包括 pid_t
#include <unistd.h>    // 引入 POSIX 操作系统API,包括 getpid(), fork() 和 sleep()int main()
{pid_t pid; // 定义一个pid_t类型变量来存储fork()的返回值int data = 10; // 定义一个整型变量data,并初始化为10while(1) { // 无限循环printf("please input a data\n"); // 提示用户输入数据scanf("%d", &data); // 从标准输入读取一个整数到变量dataif(data == 1) { // 如果输入的数据是1pid = fork(); // 调用fork()来创建一个新的子进程if(pid > 0) {// 如果pid大于0,说明是父进程执行的代码块// 父进程不进行任何操作,继续循环等待新的输入}else if(pid == 0) {// 如果pid等于0,说明是子进程执行的代码块// 在子进程中,fork()返回0while(1) {// 子进程进入另一个无限循环,每隔3秒打印一次消息printf("do net request, pid=%d\n", getpid()); // 打印当前子进程的PIDsleep(3); // 使子进程休眠3秒}}}else {// 如果输入的数据不是1printf("wait, do nothing\n"); // 打印等待信息}}return 0; // 程序理论上不会到达这里,因为有无限循环
}

例子9    父进程和子进程分别进入循环,每隔一秒打印一条消息

#include <stdio.h>    // 引入标准输入输出库,用于打印
#include <sys/types.h> // 引入数据类型,包括 pid_t
#include <unistd.h>    // 引入 POSIX 操作系统API,包括 getpid(), fork() 和 sleep()int main()
{pid_t pid; // 定义一个pid_t类型变量来存储fork()的返回值pid = fork(); // 调用fork()来创建一个新的子进程if (pid > 0){// 如果pid大于0,说明是父进程执行的代码块// 父进程进入一个无限循环while (1) {printf("this is father print, pid = %d\n", getpid()); // 打印父进程的信息和PIDsleep(1); // 父进程休眠1秒,减缓循环速度,防止过快消耗系统资源}    }else if (pid == 0) {// 如果pid等于0,说明是子进程执行的代码块// 子进程进入一个无限循环while (1) {printf("this is child print, pid = %d\n", getpid()); // 打印子进程的信息和PIDsleep(1); // 子进程休眠1秒,同样为了减缓循环速度}    }return 0; // 程序理论上不会到达这里,因为父子进程都被设置在无限循环中
}

例子10     vfork()创建子进程

#include <stdio.h>    // 引入标准输入输出库,用于打印
#include <sys/types.h> // 引入数据类型,包括 pid_t
#include <unistd.h>    // 引入 POSIX 操作系统API,包括 getpid(), vfork() 和 sleep()int main()
{pid_t pid; // 定义一个pid_t类型变量来存储vfork()的返回值pid = vfork(); // 调用vfork()来创建一个新的子进程if (pid > 0){// 如果pid大于0,说明是父进程执行的代码块// 父进程进入一个无限循环while (1) {printf("this is father print, pid = %d\n", getpid()); // 打印父进程的信息和PIDsleep(1); // 父进程休眠1秒,减缓循环速度,防止过快消耗系统资源}    }else if (pid == 0) {// 如果pid等于0,说明是子进程执行的代码块// 子进程进入一个无限循环while (1) {printf("this is child print, pid = %d\n", getpid()); // 打印子进程的信息和PIDsleep(1); // 子进程休眠1秒,同样为了减缓循环速度}    }return 0; // 程序理论上不会到达这里,因为父子进程都被设置在无限循环中
}

例子11    vfork() 创建子进程,执行一定次数后会自行退出

#include <stdio.h>    // 引入标准输入输出库,用于打印
#include <sys/types.h> // 引入数据类型,包括 pid_t
#include <unistd.h>    // 引入 POSIX 操作系统API,包括 getpid(), vfork() 和 sleep()
#include <stdlib.h>    // 引入标准库,用于 exit()int main()
{pid_t pid; // 定义一个pid_t类型变量来存储vfork()的返回值int cnt = 0; // 定义并初始化计数器pid = vfork(); // 调用vfork()来创建一个新的子进程if (pid > 0){// 如果pid大于0,说明是父进程执行的代码块// 父进程进入一个无限循环while (1) {printf("cnt=%d\n", cnt); // 打印父进程中的计数器值printf("this is father print, pid = %d\n", getpid()); // 打印父进程的信息和PIDsleep(1); // 父进程休眠1秒,减缓循环速度}    }else if (pid == 0) {// 如果pid等于0,说明是子进程执行的代码块// 子进程进入一个无限循环while (1) {printf("this is child print, pid = %d\n", getpid()); // 打印子进程的信息和PIDsleep(1); // 子进程休眠1秒cnt++; // 子进程中的计数器增加if (cnt == 3) {exit(0); // 当计数器达到3时,子进程退出break;   // 退出循环}}    }return 0; // 程序理论上不会到达这里,因为父子进程都被设置在无限循环中
}

例子12    

例子13    创建子进程,父子不同的操作。子在一定条件下会自行退出

#include <stdio.h>    // 引入标准输入输出库,用于打印
#include <sys/types.h> // 引入数据类型,包括 pid_t
#include <unistd.h>    // 引入 POSIX 操作系统API,包括 getpid(), fork() 和 sleep()
#include <stdlib.h>    // 引入标准库,用于 exit()int main()
{pid_t pid; // 定义一个pid_t类型变量来存储fork()的返回值int cnt = 0; // 定义并初始化计数器pid = fork(); // 调用fork()来创建一个新的子进程if (pid > 0){// 如果pid大于0,说明是父进程执行的代码块// 父进程进入一个无限循环while (1) {printf("cnt=%d\n", cnt); // 打印父进程中的计数器值printf("this is father print, pid = %d\n", getpid()); // 打印父进程的信息和PIDsleep(1); // 父进程休眠1秒,减缓循环速度}    }else if (pid == 0) {// 如果pid等于0,说明是子进程执行的代码块// 子进程进入一个无限循环while (1) {printf("this is child print, pid = %d\n", getpid()); // 打印子进程的信息和PIDsleep(1); // 子进程休眠1秒cnt++; // 子进程中的计数器增加if (cnt == 5) {exit(0); // 当计数器达到5时,子进程退出}}    }return 0; // 程序理论上不会到达这里,因为父子进程都被设置在无限循环中
}

例子14    父等待子进程结束后继续执行

#include <stdio.h>    // 引入标准输入输出库,用于打印
#include <sys/types.h> // 引入数据类型,包括 pid_t
#include <unistd.h>    // 引入 POSIX 操作系统API,包括 getpid(), fork() 和 sleep()
#include <stdlib.h>    // 引入标准库,用于 exit()
#include <sys/wait.h>  // 引入 wait() 函数需要的库int main()
{pid_t pid; // 定义一个pid_t类型变量来存储fork()的返回值int cnt = 0; // 定义并初始化计数器pid = fork(); // 调用fork()来创建一个新的子进程if (pid > 0){// 如果pid大于0,说明是父进程执行的代码块wait(NULL);  // 父进程等待任何子进程结束,这里不关心子进程的退出状态// 父进程在子进程结束后继续执行while (1) {printf("cnt=%d\n", cnt); // 打印父进程中的计数器值printf("this is father print, pid = %d\n", getpid()); // 打印父进程的信息和PIDsleep(1); // 父进程休眠1秒,减缓循环速度}    }else if (pid == 0) {// 如果pid等于0,说明是子进程执行的代码块// 子进程进入一个无限循环while (1) {printf("this is child print, pid = %d\n", getpid()); // 打印子进程的信息和PIDsleep(1); // 子进程休眠1秒cnt++; // 子进程中的计数器增加if (cnt == 5) {exit(0); // 当计数器达到5时,子进程退出}}    }return 0; // 程序理论上不会到达这里,因为父子进程都被设置在无限循环中
}

例子15    wait() 父等待子结束,父打印子进程的退出状态

#include <stdio.h>    // 引入标准输入输出库,用于打印
#include <sys/types.h> // 引入数据类型,包括 pid_t
#include <unistd.h>    // 引入 POSIX 操作系统API,包括 getpid(), fork() 和 sleep()
#include <stdlib.h>    // 引入标准库,用于 exit()
#include <sys/wait.h>  // 引入 wait() 函数所需的库int main()
{pid_t pid; // 定义一个pid_t类型变量来存储fork()的返回值int cnt = 0; // 定义并初始化计数器int status = 10; // 定义一个整数来存储子进程的退出状态pid = fork(); // 调用fork()来创建一个新的子进程if (pid > 0){// 如果pid大于0,说明是父进程执行的代码块wait(&status); // 父进程等待子进程结束,并通过status变量获取子进程的退出状态printf("child quit, child status = %d\n", WEXITSTATUS(status)); // 打印子进程的退出状态// 父进程在子进程结束后继续执行while (1) {printf("cnt=%d\n", cnt); // 打印父进程中的计数器值printf("this is father print, pid = %d\n", getpid()); // 打印父进程的信息和PIDsleep(1); // 父进程休眠1秒,减缓循环速度}    }else if (pid == 0) {// 如果pid等于0,说明是子进程执行的代码块// 子进程进入一个无限循环while (1) {printf("this is child print, pid = %d\n", getpid()); // 打印子进程的信息和PIDsleep(1); // 子进程休眠1秒cnt++; // 子进程中的计数器增加if (cnt == 5) {exit(3); // 当计数器达到5时,子进程退出并返回状态码3}}    }return 0; // 程序理论上不会到达这里,因为父子进程都被设置在无限循环中
}

例子16   waitpid替代 wait检查子状态,waitpid允许父进程进行非阻塞检查或等待特定的子进程结束

#include <stdio.h>    // 引入标准输入输出库,用于打印
#include <sys/types.h> // 引入数据类型,包括 pid_t
#include <unistd.h>    // 引入 POSIX 操作系统API,包括 getpid(), fork() 和 sleep()
#include <stdlib.h>    // 引入标准库,用于 exit()
#include <sys/wait.h>  // 引入等待函数库,用于 waitpid()int main()
{pid_t pid; // 定义一个pid_t类型变量来存储fork()的返回值int cnt = 0; // 定义并初始化计数器int status = 10; // 定义一个整数来存储子进程的退出状态pid = fork(); // 调用fork()来创建一个新的子进程if (pid > 0){// 如果pid大于0,说明是父进程执行的代码块waitpid(pid, &status, WNOHANG); // 使用非阻塞方式等待子进程结束,不会挂起父进程printf("child quit, child status = %d\n", WEXITSTATUS(status)); // 打印子进程的退出状态// 父进程在子进程结束后继续执行while (1) {printf("cnt=%d\n", cnt); // 打印父进程中的计数器值printf("this is father print, pid = %d\n", getpid()); // 打印父进程的信息和PIDsleep(1); // 父进程休眠1秒,减缓循环速度}    }else if (pid == 0) {// 如果pid等于0,说明是子进程执行的代码块// 子进程进入一个无限循环while (1) {printf("this is child print, pid = %d\n", getpid()); // 打印子进程的信息和PIDsleep(1); // 子进程休眠1秒cnt++; // 子进程中的计数器增加if (cnt == 5) {exit(3); // 当计数器达到5时,子进程退出并返回状态码3}}    }return 0; // 程序理论上不会到达这里,因为父子进程都被设置在无限循环中
}

例子17   子在一定条件下会自行退出,而父进程仅打印一次信息

#include <stdio.h>    // 引入标准输入输出库,用于打印
#include <sys/types.h> // 引入数据类型,包括 pid_t
#include <unistd.h>    // 引入 POSIX 操作系统API,包括 getpid(), getppid(), fork() 和 sleep()
#include <stdlib.h>    // 引入标准库,用于 exit()int main()
{pid_t pid; // 定义一个pid_t类型变量来存储fork()的返回值int cnt = 0; // 定义并初始化计数器pid = fork(); // 调用fork()来创建一个新的子进程if (pid > 0){// 如果pid大于0,说明是父进程执行的代码块printf("this is father print, pid = %d\n", getpid()); // 打印父进程的信息和PID// 父进程没有进入循环,将直接结束执行}else if (pid == 0) {// 如果pid等于0,说明是子进程执行的代码块// 子进程进入一个无限循环,直到cnt等于5while (1) {printf("this is child print, pid = %d, my father pid=%d\n", getpid(), getppid()); // 打印子进程的信息和其父进程的PIDsleep(1); // 子进程休眠1秒cnt++; // 子进程中的计数器增加if (cnt == 5) {exit(3); // 当计数器达到5时,子进程退出并返回状态码3}}    }return 0; // 父进程执行完打印后将结束,子进程在计数达到5后也将结束
}

例子18   execl执行一个新的程序。这个函数属于 exec 系列函数,它们用于替换当前进程的映像

#include <stdio.h>    // 引入标准输入输出库,用于打印
#include <stdlib.h>   // 引入标准库,用于标准库功能
#include <unistd.h>   // 引入 POSIX 操作系统API,包括 execl()// 函数原型:int execl(const char *path, const char *arg, ...);int main(void)
{// 打印 "before execl" 表明当前在调用 execl 前printf("before execl\n");// 调用 execl 执行名为 "echoarg" 的程序,该程序应在当前目录下// "echoarg" 是被执行程序的名称,同时也是传递给该程序的第一个参数// "abc" 是传递给 echoarg 程序的第二个参数// NULL 表示参数列表的结束if(execl("./echoarg", "echoarg", "abc", NULL) == -1){// 如果 execl 返回 -1,则表示执行失败printf("execl failed!\n");// perror 用于打印上一个函数调用的错误描述(基于全局的 errno 变量)perror("why");}// 由于 execl 成功时不返回,如果程序执行到这里说明 execl 调用失败printf("after execl\n");return 0;
}

例子19    execl函数来执行 /bin/ls 命令,通常用于列出目录内容。如果 execl() 调用成功,则不会返回;如果调用失败,会返回 -1 并打印错误信息

#include <stdio.h>    // 引入标准输入输出库,用于打印
#include <stdlib.h>   // 引入标准库,用于标准库功能
#include <unistd.h>   // 引入 POSIX 操作系统API,包括 execl()// 函数原型:int execl(const char *path, const char *arg, ...);int main(void)
{// 打印 "before execl" 表明当前在调用 execl 前printf("before execl\n");// 调用 execl 执行位于 "/bin/ls" 的程序,通常用于列出目录内容// "ls" 是传递给 /bin/ls 程序的参数,用于识别程序名称// NULL 指示参数列表的结束if(execl("/bin/ls", "ls", NULL, NULL) == -1){// 如果 execl 返回 -1,则表示执行失败printf("execl failed!\n");      // perror 用于打印上一个函数调用的错误描述(基于全局的 errno 变量)perror("why");}// 由于 execl 成功时不返回,如果程序执行到这里说明 execl 调用失败printf("after execl\n");return 0;
}

例子20    execl函数来执行 /bin/ls 命令,配上 -l 选项来以长格式列出目录内容。如果 execl() 调用成功,则会替换当前进程的映像并不返回;如果失败,会返回 -1 并打印错误信息

#include <stdio.h>    // 引入标准输入输出库,用于打印
#include <stdlib.h>   // 引入标准库,用于标准库功能
#include <unistd.h>   // 引入 POSIX 操作系统API,包括 execl()// 函数原型:int execl(const char *path, const char *arg, ...);int main(void)
{// 打印 "before execl" 表明当前在调用 execl 前printf("before execl\n");// 调用 execl 执行位于 "/bin/ls" 的程序,使用 "-l" 选项来以详细列表格式列出文件和目录// "ls" 是传递给 /bin/ls 程序的参数,用于识别程序名称// "-l" 是一个参数,告诉 ls 命令以长格式显示信息// NULL 指示参数列表的结束if(execl("/bin/ls", "ls", "-l", NULL) == -1){// 如果 execl 返回 -1,则表示执行失败printf("execl failed!\n");      // perror 用于打印上一个函数调用的错误描述(基于全局的 errno 变量)perror("why");}// 由于 execl 成功时不返回,如果程序执行到这里说明 execl 调用失败printf("after execl\n");return 0;
}

例子21    execl()执行系统命令 /bin/date,该命令用于显示当前系统日期和时间。如果 execl()调用成功,它会替换当前进程的映像为 /bin/date 并不返回;如果失败,会返回 -1 并打印错误信息

#include <stdio.h>    // 引入标准输入输出库,用于打印
#include <stdlib.h>   // 引入标准库,用于标准库功能
#include <unistd.h>   // 引入 POSIX 操作系统API,包括 execl()// 函数原型:int execl(const char *path, const char *arg, ...);int main(void)
{// 打印信息,表明程序意图获取当前系统日期printf("this pro get system date:\n");// 调用 execl 执行位于 "/bin/date" 的系统命令// "date" 是传递给 /bin/date 程序的参数,用于识别程序名称// NULL 指示参数列表的结束if(execl("/bin/date", "date", NULL, NULL) == -1){// 如果 execl 返回 -1,则表示执行失败printf("execl failed!\n");      // perror 用于打印上一个函数调用的错误描述(基于全局的 errno 变量)perror("why");}// 由于 execl 成功时不返回,如果程序执行到这里说明 execl 调用失败printf("after execl\n");return 0;
}

例子22    execlp()执行系统命令 ps,该命令用于显示当前系统的进程状态。如果 execlp() 调用成功,它会替换当前进程的映像为 ps 命令并不返回;如果失败,会返回 -1 并打印错误信息

#include <stdio.h>    // 引入标准输入输出库,用于打印
#include <stdlib.h>   // 引入标准库,用于标准库功能
#include <unistd.h>   // 引入 POSIX 操作系统API,包括 execlp()// 函数原型:int execl(const char *path, const char *arg, ...);int main(void)
{// 打印信息,表明程序意图获取当前系统进程状态printf("this pro get system date:\n");// 调用 execlp 执行系统命令 "ps"// "ps" 是传递给 execlp() 的参数,用于执行 ps 命令显示进程信息// NULL 指示参数列表的结束if(execlp("ps", "ps", NULL, NULL) == -1){// 如果 execlp 返回 -1,则表示执行失败printf("execl failed!\n");// perror 用于打印上一个函数调用的错误描述(基于全局的 errno 变量)perror("why");}// 由于 execlp 成功时不返回,如果程序执行到这里说明 execlp 调用失败printf("after execl\n");return 0;
}

例子23    execvp()执行系统命令 ps,用于显示当前系统的进程状态。execvp() 类似于 execlp(),但允许通过一个参数数组来传递命令和其参数。如果 execvp() 调用成功,它会替换当前进程的映像为 ps 命令并不返回;如果失败,会返回 -1 并打印错误信息

#include <stdio.h>    // 引入标准输入输出库,用于打印
#include <stdlib.h>   // 引入标准库,用于标准库功能
#include <unistd.h>   // 引入 POSIX 操作系统API,包括 execvp()// 函数原型:int execvp(const char *file, char *const argv[]);int main(void)
{// 打印信息,表明程序意图获取当前系统进程状态printf("this pro get system date:\n");// 创建参数数组,用于传递给 execvp()char *argv[] = {"ps", NULL, NULL};// 调用 execvp 执行系统命令 "ps"// "ps" 是传递给 execvp() 的命令,argv 是命令和参数的数组if(execvp("ps", argv) == -1){// 如果 execvp 返回 -1,则表示执行失败printf("execl failed!\n");      // perror 用于打印上一个函数调用的错误描述(基于全局的 errno 变量)perror("why");}// 由于 execvp 成功时不返回,如果程序执行到这里说明 execvp 调用失败printf("after execl\n");return 0;
}

例子24    execv()执行 /bin/ps 命令,该命令用于显示当前系统的进程状态。execv() 类似于 execl(),但使用数组来传递命令和其参数。如果 execv() 调用成功,它会替换当前进程的映像为 /bin/ps 并不返回;如果失败,会返回 -1 并打印错误信息

#include <stdio.h>    // 引入标准输入输出库,用于打印
#include <stdlib.h>   // 引入标准库,用于标准库功能
#include <unistd.h>   // 引入 POSIX 操作系统API,包括 execv()// 函数原型:int execv(const char *path, char *const argv[]);int main(void)
{// 打印信息,表明程序意图获取当前系统进程状态printf("this pro get system date:\n");// 创建参数数组,用于传递给 execv()char *argv[] = {"ps", NULL, NULL};  // "ps" 是命令名,NULL 表示参数列表结束// 调用 execv 执行位于 "/bin/ps" 的系统命令// "/bin/ps" 是命令的完整路径// argv 是命令和参数的数组if(execv("/bin/ps", argv) == -1){// 如果 execv 返回 -1,则表示执行失败printf("execl failed!\n");// perror 用于打印上一个函数调用的错误描述(基于全局的 errno 变量)perror("why");}// 由于 execv 成功时不返回,如果程序执行到这里说明 execv 调用失败printf("after execl\n");return 0;
}

例子25  输入来触发文件操作,在子进程中进行。这个例子特别是在输入为 1 时,程序会修改配置文件 config.txt 中的一个特定值

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>int main()
{pid_t pid;  // 用于存储进程IDint data = 10;  // 用户输入的数据初始化为10while(1) {  // 无限循环,直到程序被外部方式终止printf("please input a data\n");  // 提示用户输入数据scanf("%d", &data);  // 读取用户输入的整数数据if(data == 1) {  // 如果输入的数据为1,则进行文件操作int fdSrc;  // 文件描述符pid = fork();  // 创建子进程if(pid > 0) {wait(NULL);  // 父进程等待子进程完成}if(pid == 0) {  // 子进程代码块char *readBuf = NULL;  // 读缓冲区指针fdSrc = open("config.txt", O_RDWR);  // 打开文件config.txt进行读写操作int size = lseek(fdSrc, 0, SEEK_END);  // 获取文件大小lseek(fdSrc, 0, SEEK_SET);  // 将文件指针重置到文件开始readBuf = (char *)malloc(sizeof(char) * size + 8);  // 分配读缓冲区内存int n_read = read(fdSrc, readBuf, size);  // 读取文件内容到缓冲区char *p = strstr(readBuf, "LENG=");  // 在缓冲区中查找"LENG="if(p == NULL) {printf("not found\n");  // 如果没有找到,打印未找到并退出exit(-1);}p = p + strlen("LENG=");  // 移动指针到"LENG="之后*p = '5';  // 修改内容lseek(fdSrc, 0, SEEK_SET);  // 将文件指针重置到文件开始int n_write = write(fdSrc, readBuf, strlen(readBuf));  // 将修改后的缓冲区内容写回文件close(fdSrc);  // 关闭文件exit(0);  // 子进程退出}} else {printf("wait, do nothing\n");  // 如果输入不是1,提示等待}}return 0;  // 主程序循环,实际上这里永远不会执行到
}

例子26    根据输入决定是否创建一个子进程来执行特定的程序 (changData),该程序预期对 config.txt 文件进行修改。如果输入不是 1,则打印消息并继续等待

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>int main()
{pid_t pid;  // 用于存储进程IDint data = 10;  // 用户输入的数据初始化为10while(1) {  // 无限循环,直到程序被外部方式终止printf("please input a data\n");  // 提示用户输入数据scanf("%d", &data);  // 读取用户输入的整数数据if(data == 1) {  // 如果输入的数据为1,则进行操作int fdSrc;  // 文件描述符,虽然在此代码版本中未被使用pid = fork();  // 创建子进程if(pid > 0) {wait(NULL);  // 父进程等待子进程完成}if(pid == 0) {  // 子进程代码块// 子进程执行一个外部程序 "changData"// 第一个参数 "./changData" 指定了程序的路径// 第二个参数 "changData" 是传递给程序的 argv[0],即程序名// 第三个参数 "config.txt" 是传递给 changData 程序的参数,指定要操作的文件// NULL 表示参数列表的结束execl("./changData", "changData", "config.txt", NULL);// 如果execl执行失败,则会继续执行以下代码perror("Failed to execute changData");  // 打印执行失败的原因exit(1);  // 子进程失败时退出}} else {printf("wait, do nothing\n");  // 如果输入不是1,提示等待并什么也不做}}return 0;  // 主程序循环,实际上这里永远不会执行到
}

例子27    根据输入决定执行一个外部命令(changData),该命令与配置文件 config.txt 相关联。如果用户输入 1,程序会创建一个子进程,该子进程通过 system 函数调用外部程序 ./changData 来处理文件 config.txt

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>int main()
{pid_t pid;  // 用于存储进程IDint data = 10;  // 用户输入的数据初始化为10while(1) {  // 无限循环,直到程序被外部方式终止printf("please input a data\n");  // 提示用户输入数据scanf("%d", &data);  // 读取用户输入的整数数据if(data == 1) {  // 如果输入的数据为1,则进行操作int fdSrc;  // 文件描述符,虽然在此代码版本中未被使用pid = fork();  // 创建子进程if(pid > 0) {wait(NULL);  // 父进程等待子进程完成}if(pid == 0) {  // 子进程代码块// 子进程执行一个外部程序 "changData" 通过 system 函数// "./changData config.txt" 是被调用的命令,传递 'config.txt' 作为参数system("./changData config.txt");exit(0);  // 执行完外部命令后,子进程应正常退出}} else {printf("wait, do nothing\n");  // 如果输入不是1,提示等待并什么也不做}}return 0;  // 主程序循环,实际上这里永远不会执行到
}

例子28    system() 执行系统命令(在本例中是 ps),这个命令用来列出当前运行的进程。然而,该代码示例存在一个问题:它没有捕获 system() 调用的输出

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
//函数原型:int execl(const char *path, const char *arg, ...);int main(void)
{char ret[1024] = {0};  // 定义一个字符数组并初始化所有元素为0,用于存储输出system("ps");  // 调用system函数执行ps命令,ps命令用于显示当前运行的进程// 注意:system函数实际上不会将命令输出存储在ret数组中printf("ret=%s\n", ret);  // 打印ret数组的内容,预期输出为空字符串,因为system不会更改retreturn 0;
}

例子29   popen() 和 fread() 函数从 ps 命令获取输出并将其读入到一个字符数组中。该程序展示了如何执行系统命令并捕获其输出,适合需要从命令行工具中直接读取数据的场景

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
// 函数原型:int execl(const char *path, const char *arg, ...);
// size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream)int main(void)
{char ret[1024] = {0};  // 创建字符数组,用于存储命令输出FILE *fp;  // 文件指针,用于执行 popen() 返回的流// 执行 'ps' 命令,并打开用于读取的管道fp = popen("ps", "r");if (fp == NULL) {  // 检查 popen 是否成功打开了管道perror("Failed to run command");  // 打印 popen 执行失败的错误详情exit(1);  // 退出程序}// 从 'ps' 命令的输出流中读取数据到 ret 数组中int nread = fread(ret, 1, 1024, fp);  // 读取最多 1024 个字节到 ret// 打印读取的字节数和内容printf("read ret %d byte, ret=%s\n", nread, ret);// 关闭管道pclose(fp);return 0;
}

例子30   处理命令行参数。它通过遍历 argc 和 argv 数组来打印所有传递给程序的参数

#include <stdio.h>int main(int argc, char *argv[])  // main 函数接受命令行参数:argc 表示参数数量,argv 是参数字符串数组
{int i = 0;  // 定义循环计数变量for(i = 0; i < argc; i++)  // 循环遍历所有命令行参数{printf("argv[%d]: %s\n", i, argv[i]);  // 打印每个参数的索引和内容}return 0;  // 程序正常结束
}

例子31   等待用户输入。当用户输入 1 时,程序会创建一个子进程,这个子进程会修改一个文件(./file1)中特定字符串("LENG=")之后的字符

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>int main()
{pid_t pid;  // 用于存储进程IDint data = 10;  // 用户输入的数据初始化为10while(1) {  // 无限循环,直到程序被外部方式终止printf("please input a data\n");  // 提示用户输入数据scanf("%d", &data);  // 读取用户输入的整数数据if(data == 1) {  // 如果输入的数据为1,则进行操作pid = fork();  // 创建子进程if(pid > 0) {// 父进程执行的代码块// 父进程不做任何操作,继续循环等待下一次输入}else if(pid == 0) {// 子进程执行的代码块char *readBuf = NULL;  // 读缓冲区指针int fdSrc;  // 文件描述符fdSrc = open("./file1", O_RDWR);  // 打开文件file1进行读写操作int size = lseek(fdSrc, 0, SEEK_END);  // 获取文件大小lseek(fdSrc, 0, SEEK_SET);  // 将文件指针重置到文件开始readBuf = (char *)malloc(sizeof(char) * size + 8);  // 分配读缓冲区内存int n_read = read(fdSrc, readBuf, size);  // 读取文件内容到缓冲区char *p = strstr(readBuf, "LENG=");  // 在缓冲区中查找"LENG="if(p == NULL) {printf("not found\n");  // 如果没有找到,打印未找到并退出exit(-1);}p += strlen("LENG=");  // 移动指针到"LENG="之后*p = '5';  // 修改内容lseek(fdSrc, 0, SEEK_SET);  // 将文件指针重置到文件开始int n_write = write(fdSrc, readBuf, strlen(readBuf));  // 将修改后的缓冲区内容写回文件close(fdSrc);  // 关闭文件free(readBuf); // 释放分配的内存exit(0);  // 子进程退出}}else {printf("wait, do nothing\n");  // 如果输入不是1,提示等待并什么也不做}}return 0;  // 主程序循环,实际上这里永远不会执行到
}

例子32    execl()函数是为了替换当前的进程映像为/bin/ls命令的进程映像

#include <stdio.h>   // 引入标准输入输出头文件。
#include <stdlib.h>  // 引入标准库头文件,用于执行一些常规的函数操作,比如exit()。
#include <unistd.h>  // 引入UNIX标准函数定义头文件,提供对POSIX操作系统API的访问。// 函数原型声明:int execl(const char *path, const char *arg, ...);
// execl()函数用于执行指定的文件路径,将当前进程替换为一个新的进程。int main(void)
{printf("before execl\n");  // 在调用execl()前打印信息。// 调用execl()尝试执行/bin/ls命令来列出目录内容。"ls"是命令名,"-l"是参数。if(execl("/bin/ls", "ls", "-l", NULL) == -1){printf("execl failed!\n");  // 如果execl()返回-1,则说明执行失败。perror("why");  // 使用perror()函数输出错误原因。perror()会根据全局错误码errno输出错误描述。}// 如果execl()函数调用成功,则不会执行以下代码,因为execl()会替换当前进程的映像,不会返回。printf("after execl\n");  // 如果execl()失败,会继续执行这里的代码。return 0;  // 程序正常结束。
}

例子33   vfork()创建子进程并控制执行顺序

#include <stdio.h>   // 引入标准输入输出头文件,用于printf函数。
#include <sys/types.h>  // 引入数据类型定义,例如pid_t。
#include <unistd.h>  // 引入POSIX操作系统API,例如vfork和getpid函数。
#include <stdlib.h>  // 引入标准库头文件,用于执行一些常规的函数操作,如exit()。int main()
{pid_t pid;  // 声明一个pid_t类型的变量来存储进程ID。int cnt = 0;  // 计数器,用于子进程中记录循环次数。pid = vfork();  // 创建一个子进程,子进程与父进程共享内存空间。if (pid > 0)  // 如果pid大于0,表示当前代码块在父进程中执行。{while (1) {  // 父进程无限循环。printf("cnt=%d\n", cnt);  // 打印当前计数器的值(注意:这个值在父进程中不会改变)。printf("this is father print, pid = %d\n", getpid());  // 打印父进程的ID。sleep(1);  // 暂停父进程1秒,以便观察输出。}   }else if (pid == 0) {  // 如果pid等于0,表示当前代码块在子进程中执行。while (1) {  // 子进程无限循环。printf("this is child print, pid = %d\n", getpid());  // 打印子进程的ID。sleep(1);  // 暂停子进程1秒,以便观察输出。cnt++;  // 子进程中计数器递增。if (cnt == 3) {  // 如果计数器达到3,子进程退出。exit(0);  // 调用exit函数,正常终止子进程。}}   }return 0;  // 主程序结束(通常这个部分不会被执行到,因为父子进程已经进入了无限循环)。
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/21744.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

混合动力电动汽车介绍(二)

接续前一章内容&#xff0c;本篇文章介绍混合动力汽车串联、并联和混联的系统组成和工作原理。 一、串联混合动力电动汽车的系统组成和工作原理 上图为串联混合动力电动汽车的结构简图。汽车由电动机-发电机驱动行驶&#xff0c;电机控制器的动力来自油箱-发动机-发电机-发电机…

Python 爬虫零基础:探索网络数据的神秘世界

Python 爬虫零基础&#xff1a;探索网络数据的神秘世界 在数字化时代&#xff0c;网络数据如同无尽的宝藏&#xff0c;等待着我们去发掘。Python爬虫&#xff0c;作为获取这些数据的重要工具&#xff0c;正逐渐走进越来越多人的视野。对于零基础的学习者来说&#xff0c;如何入…

基于Spring Boot框架的分页查询和文件上传

分页查询 分析 要想从数据库中进行分页查询&#xff0c;我们要使用LIMIT关键字&#xff0c;格式为&#xff1a;limit 开始索引 每页显示的条数 假设一页想展示10条数据 查询第1页数据的SQL语句是&#xff1a; select * from emp limit 0,10; 查询第2页数据的SQL语句是&…

【Pytest官方文档翻译及学习】2.2 如何在测试中编写和报告断言

目录 2.2 如何在测试中编写和报告断言 2.2.1 使用assert语句断言 2.2.2 关于预期异常的断言 2.2.3 关于预期警告的断言 2.2.4 应用上下文相关的比较 2.2.5 为失败的断言定义自己的解释 2.2.6 断言内省细节 2.2 如何在测试中编写和报告断言 2.2.1 使用assert语句断言 p…

6、架构-服务端缓存

为系统引入缓存之前&#xff0c;第一件事情是确认系统是否真的需要缓 存。从开发角度来说&#xff0c;引入缓存会提 高系统复杂度&#xff0c;因为你要考虑缓存的失效、更新、一致性等问题&#xff1b;从运维角度来说&#xff0c;缓存会掩盖一些缺 陷&#xff0c;让问题在更久的…

npm彻底清理缓存

在使用npm过程中&#xff0c;肯定会遇到清缓存的情况&#xff0c;网上的命令一般为 npm cache clear --force有时笔者在清理缓存之后npm install依然失败&#xff0c;仔细发现&#xff0c;执行该命令之后npm报了一个警告 npm WARN using --force Recommended protections dis…

代码随想录算法训练营第27天|● 39. 组合总和● 40.组合总和II● 131.分割回文串

组合总和 题目链接 39. 组合总和 - 力扣&#xff08;LeetCode&#xff09; 代码&#xff1a; class Solution {public List<List<Integer>> res new ArrayList<>();public List<Integer> list new ArrayList<>();public int sum 0;/**…

在nginx中配置反向代理

在nginx中配置反向代理&#xff0c;需要使用proxy_pass指令。以下是一个简单的nginx反向代理配置示例&#xff1a; server {listen 80;server_name example.com;location / {proxy_pass http://backend_server;proxy_set_header Host $host;proxy_set_header X-Real-IP $remote…

LoadRunner 录制脚本时提示无Internet访问/加载慢,如何解决?

LoadRunner 录制脚本时提示无Internet访问/加载慢&#xff0c;如何解决&#xff1f; 在使用LoadRunner 12.02 进行录制脚本时提示无Internet访问&#xff0c;这是如下图&#xff1a; 翻译中文如下&#xff1a; 这里&#xff0c;我认为大家应该都已经点过yes了&#xff0c;但是…

python结构化模式匹配switch-case,Python 3.10中引入,Python的模式匹配(pattern matching)语法

增加了采用模式加上相应动作的 match 语句 和 case 语句 的形式的结构化模式匹配。 模式由序列、映射、基本数据类型以及类实例构成。 模式匹配使得程序能够从复杂的数据类型中提取信息、根据数据结构实现分支&#xff0c;并基于不同的数据形式应用特定的动作。 语法与操作 模…

Linux下配置Pytorch

1.Anaconda 1.1虚拟环境创建 2.Nvidia驱动 3.CUDA驱动安装 4.Pytorch安装 具体的步骤如上&#xff1a;可参考另一位博主的博客非常详细&#xff1a; Linux服务器配置PythonPyTorchCUDA深度学习环境_linux cuda环境配置-CSDN博客https://blog.csdn.net/NSJim/article/detai…

极海APM32F072用Keil5烧录失败Error: Flash Download failed -“Cortex-MO+“

在用Keil5烧录时&#xff0c;出现错误弹窗&#xff0c;大概长这样&#xff1a; 检查了一圈设置&#xff0c;都搞不好。 先用J-Flash&#xff0c;显示读写保护&#xff08;未截图&#xff09;&#xff0c;会跳出界面让选择是否解除读写保护&#xff1a; 1.点击允许读操作YES&am…

DNF手游攻略:0氪攻略,转职技巧与避坑指南!

在DNF手游的冒险旅程中&#xff0c;角色的转职是一次重要的成长经历。通过转职&#xff0c;玩家可以获得全新的技能和属性&#xff0c;提升自己在地下城中的战斗力。本文将为您介绍转职后的关键技巧和日常任务&#xff0c;帮助您更好地适应新的职业身份&#xff0c;成为地下城中…

Python从0到100(二十九):requests模块处理cookie

1 爬虫中使用cookie 为了能够通过爬虫获取到登录后的页面&#xff0c;或者是解决通过cookie的反扒&#xff0c;需要使用request来处理cookie相关的请求 1.1 爬虫中使用cookie的利弊 带上cookie的好处 能够访问登录后的页面能够实现部分反反爬 带上cookie的坏处 一套cookie往往…

数据库与低代码开发:技术革新与应用实践

在数字化时代&#xff0c;企业对软件开发的需求日益增长&#xff0c;同时对开发效率和成本控制的要求也越来越高。在这样的背景下&#xff0c;低代码开发平台应运而生&#xff0c;它允许开发者通过图形界面和配置化操作&#xff0c;快速构建应用程序&#xff0c;而无需编写大量…

【设计模式】JAVA Design Patterns——Monitor(监视器模式)

&#x1f50d;目的 主要目的是为多个线程或进程提供一种结构化和受控的方式来安全地访问和操作共享资源&#xff0c;例如变量、数据结构或代码的关键部分&#xff0c;而不会导致冲突或竞争条件。 &#x1f50d;解释 通俗描述 监视器模式用于强制对数据进行单线程访问。 一次只允…

Windows线程同步的四种方式和区别

1. Windows线程同步的四种方式 2. 区别 Critical Section更多强调的是保护&#xff0c;Event对象、Mutex对象与Semaphore对象更多的强调的是同步&#xff1b;Critical Section对象是无法设置等待超时的&#xff0c;而其他三个对象则可以设置等待超时&#xff0c;从这一点来讲…

ROS2在RVIZ2中加载机器人urdf模型

参考ROS2-rviz2显示模型 我这边用的solid works生成的urdf以及meshes&#xff0c;比参考的方法多了meshes 问题一&#xff1a;Error retrieving file [package://rm_dcr_description/meshes/leftarm_link7.STL]: Package [rm_dcr_description] does not exist 这个是urdf模型中…

VisualStudio中:如果某个项目不显示SVN的show log等,而其他项目都正常

VisualStudio中&#xff1a;如果某个项目不显示SVN的show log等&#xff0c;而其他项目都正常。说明大概率是当前项目的问题&#xff0c;而不是VisualStudio的问题&#xff01; 1.这个项目内有一个“隐藏”文件夹.svn 》先删除&#xff01; 2.如果外层文件夹有红色感叹号&…

2024-5-14——完成所有任务需要的最少轮数

2024-5-14 题目来源我的题解方法一 哈希表数学 题目来源 力扣每日一题&#xff1b;题序&#xff1a;2244 我的题解 方法一 哈希表数学 根据数学规律可以发现&#xff0c;除了只有1个任务时不能完成任务&#xff0c;其他的都可以完成。并且需要的轮数为&#xff1a; ⌈x/3⌉ …