怎么用代码创建网站教程,天门市住房和城乡建设网站,移动网站 做优化,网站开发实施方案嵌入式开发为什么要移植操作系统#xff1f;
1.减小软硬件的耦合度#xff0c;提高软件的移植性
2. 操作系统提供很多库和工具#xff08;QT Open CV#xff09;#xff0c;提高开发效率
3.操作系统提供多任务机制#xff0c;______________________? (提高C…嵌入式开发为什么要移植操作系统
1.减小软硬件的耦合度提高软件的移植性
2. 操作系统提供很多库和工具QT Open CV提高开发效率
3.操作系统提供多任务机制______________________? (提高CPU的效率
4.操作系统提供了丰富的网络协议栈实现远程传输 Linux C 多进程编程多进程、多线程
1.什么是多任务
单任务————多任务
并发————并行
单核CPU ————多核CPU 2.多任务操作的实现方式
进程和线程 程序和进程的区别 程序 是一组指令和数据的集合是静态的、存储在磁盘或其他存储介质上的文件。
程序可以被看作是一段代码的集合描述了在计算机上执行的任务。
程序本身是静态的需要加载到内存中才能执行。 进程
是程序的抽象
是动态的
每个进程都都有独立的运行空间虚拟地址空间
每个进程都是一个独立的运行单位拥有各自的权力和责任互不干扰
进程是 安全的任务机制
缺点:开销大进程创建和进程切换 进程PID编号
父进程创建子进程
获取进程PID
获取父进程PID ps命令、top命令和htop命令 进程调度
在许多个已经处于就绪态的进程中选择决定哪个进程进行调度基于进程三态
进程状态
就绪态、执行态和等待态阻塞态 操作系统的核心就是任务进程管理 主要分为两大类抢占式设置优先级和非抢占式不设置优先级
有如下策略
1.先到先服务 2.短进程优先 3.时间片轮转使用最多 4.高优先级优先 实时操作系统是一种响应速度快准确性高抢占式
不同任务之间通过双向链表链接 进程分类 处理器消耗型 渴望获取更多的CPU时间并消耗掉调度器分配的全部时间片·常见例子:无限死循环、科学计算、影视特效渲染 I/O消耗型 由于等待某种资源通常处于阻塞状态不需要较长的时间片 常见例子:等待用户输入、GUI程序、文件读写I/O程序 进程同步
多个进程访问同一个文件时需要互斥访问否则易产生错误
操作系统把一次只允许一个进程访问的资源成为临界资源需要互斥访问 进程的创建
1.fork函数 作业利用多进程实现分别从键盘和鼠标读数据
#include unistd.h
#include stdio.h
#include sys/types.h
#include errno.h
#include string.h
#include stdlib.h
#include sys/types.h
#include fcntl.hint main(int argc, char **argv)
{int count 0;pid_t pid fork();if (pid 0) // 错误处理{perror(pid error);exit(-1);}if (pid 0) // 父进程执行鼠标读操作{int fd1 open(/dev/input/mouse0, O_RDWR);if (fd1 -1){perror(fd1 error);exit(-1);}int location 0;while (1){int r_num1 read(fd1, location, sizeof(int));if (r_num1 0){printf(mouse loaction%d\n, location);}}}if (pid 0) // 子进程执行键盘读写操作{char buffer[1024];memset(buffer, 0, sizeof(buffer));while (1){int r_num (read(0, buffer, sizeof(buffer) - 1));if (r_num 0){buffer[r_num] \0;printf(%s\n, buffer);}memset(buffer, 0, sizeof(buffer));}}return 0;
}
通过多进程实现父子进程对同一个文件进行写操作
#include unistd.h
#include stdio.h
#include sys/types.h
#include errno.h
#include string.h
#include stdlib.h
#include sys/types.h
#include fcntl.hint main(int argc, char **argv)
{int count 0;int fd open(a.txt, O_RDWR | O_APPEND | O_CREAT, 0777);if (fd -1){perror(fd error);exit(-1);}pid_t pid fork();if (pid 0) // 错误处理{perror(pid error);exit(-1);}if (pid 0) // 父进程操作{write(fd, hello, 5);write(fd, world, 5);write(fd, \n, 1);}if (pid 0) // 子进程执行操作{write(fd, FFFFF, 5);write(fd, KKKKK, 5);write(fd, \n, 1);}return 0;
}
父子进程的运行顺序暂时是不需要明白内部有进程调度算法 2.exec函数族
使用execl函数时原函数在execl函数后的代码段会不起作用
表头文件:#include unistd.h
1. int execl c const char *pathconst char *arg...) 函数说明:
execl()用来执行参数path字符串所代表的文件路径接下来的参数代表执行该文件时传递过去的argv[0]、argv[1]……最后一个参数必须用空指针(NULL)作结束。 返回值﹔如果执行成功则函数不会返回执行失败则直接返回-1失败原因存于errno中 2. int execv ( const char *pathchar *const argv[]); 函数说明:
execv ()用来执行参数path字符串所代表的文件路径与execl (不同的地方在于execve (只需两个参数第二个参数系利用指针数组来传递给执行文件。 返回值﹔如果执行成功则函数不会返回执行失败则直接返回-1失败原因存于errno中。 3. int execlp (const char*fileconst char *arg,...); 函数说明: execlp ( 会从 PATH环境变量所指的目录中查找符合参数file的文件名找到后便执行该文件然后将第二个以后的参数当作该文件的argv[0]、argv[1]……最后一个参数必须用空指针NULL)作结束。 返回值﹔如果执行成功则函数不会返回执行失败则直接返回-1失败原因存于errno中。 4.int execvp ( const char *filechar *const argv[]); 函数说明: execvp ( )会从 PATH 环境变量所指的目录中查找符合参数file 的文件名找到后便执行该文件然后将第二个参数argv传给该欲执行的文件。 返回值:如果执行成功则函数不会返回执行失败则直接返回-1失败原因存于errno中。 错误代码:请参考execve ()
5.int execve ( const char *filenamechar *const argv [].char *const envp[]);
函数说明:execve ()用来执行参数filename字符串所代表的文件路径第二个参数系利用指针数组来传递给执行文件最后一个参数则为传递给执行文件的新环境变量数组。 返国值:如果执行成功则函数不会返回执行失败则直接返回-1失败原因存于errno 中。
#include unistd.h
#include stdio.h
#include sys/types.h
#include errno.h
#include string.h
#include stdlib.h
#include sys/types.h
#include fcntl.hint main(int argc, char **argv)
{// 1.参数表直接写入 以NULL结尾execl(./write1, ./write1, hello, world, NULL);// 2.参数表用指针数组的形式 以NULL结尾char *arg1[] {./write2, welcome, zhaodeming, NULL};xecv(./write2, arg1);// 3.execlp(/home/zdm/241/PROCESS_CODE/write1, ./write1, hello, world, NULL);//execlp(./write1, ./write1, hello, world, NULL); // 也可以// 4.char *arg2[] {./write2, welcome, zhaodmeing, NULL};execvp(/home/zdm/241/PROCESS_CODE/write2, arg2);// 5. e---环境变量char *env[] {USRadmin, PASSWD12345};execve(/home/zdm/241/PROCESS_CODE/write2, arg2, env);printf(exce demo ok\n);
}
每个调用exec函数会覆盖掉后面的代码 常常与fork函数联用
#include unistd.h
#include stdio.h
#include sys/types.h
#include errno.h
#include string.h
#include stdlib.h
#include sys/types.h
#include fcntl.hint main(int argc, char **argv)
{int count 0;pid_t pid fork();if (pid 0) // 错误处理{perror(pid error);exit(-1);}if (pid 0) // 父进程执行操作{execl(./write1, ./write1, hello, world, NULL);}if (pid 0) // 子进程执行操作{char *arg1[] {./write2, welcome, zhaodeming, NULL};execvp(/home/zdm/241/PROCESS_CODE/write2, arg1);}return 0;
} 3.vfork 系统调用
对fork的改进对fork的改进更为彻底、简单粗暴 vfork是为子进程立即执行exec的程序而专设计的 无需为子进程复制虚拟内存页或页表子进程直接共享父进程的资源直到其成功执行exec或是调用exit退出 在子进程调用exec之前将暂停执行父进程 子进程中无exec时则先执行子进程后执行父进程
子进程有exec函数时exec函数前的代码段先执行执行到exec函数时候父子进程调用顺序则又不确定和fork一样
#include unistd.h
#include stdio.h
#include sys/types.h
#include errno.h
#include string.h
#include stdlib.h
#include sys/types.h
#include fcntl.hint main(int argc, char **argv)
{int count 0;pid_t pid vfork();if (pid 0){perror(pid error);exit(-1);}if (pid 0){printf(%d\n,count);}if (pid 0){//count; //尽量避免在子进程中修改全局变量容易引发段错误//exit(-1); execl(./write1,./write1,NULL);}return 0;
} 4.systemconst char*command——库函数
#include stdio.h
#include stdlib.h
#includeunistd.hint main(int aargc, char **argv)
{system(./write1 system_using read);sleep(3);system(clear);sleep(3);system(ls -l);sleep(3);system(clear);sleep(3);return 0;
} 进程的退出
_exit——系统调用
更多用于异常退出不会刷新stdio缓冲区
exit——库函数
内部封装了_exit会刷新stdio缓冲区atexit/on_exit注册了退出管理程序则应使用exit 正常退出 main 调用return
异常退出 1.任意地方调用exit/_exit 2.被信号杀死 3. 调用abort函数 abort函数
以异常方式结束进程abort ( 将引起进程异常的终止此时所有已打开的文件流会自动关闭所有的缓冲区数据也会自动写回。 进程等待
回收进程资源
进程运行终止后不管进程是正常终止还是异常终止的必须回收进程所占用的资源。如何查看进程资源?
————————ps命令 为什么要回收进程的资源?
————————不回收资源会导致系统性能下降 父进程运行结束时会负责回收子进程资源 ./a.out进程的父进程是谁? 0,1,2三个进程OS启动后抑制默默运行直到关机OS结束运行
pid0的进程称作调度进程
pid1的进程 1.init进程跟前端用户做交互2.托管孤儿进程3.原始父进程位于/sbin/init目录下可以restart*stop;
pid2的进程页精灵进程 僵尸进程和孤儿进程 僵尸进程子进程终止后父进程还在运行那么在父进程没有回收子进程资源前此时的子进程就是僵尸进程 孤儿进程子进程还未结束父进程先结束子进程的资源无法回收此时子进程就是孤儿进程
为了能够回收孤进程终止后的资源孤儿进程会被托管给我们前面介绍的pid1的init进程每当被托管的子进程终止时init会立即主动回收孤儿进程资源回收资源的速度很快所以孤儿进程没有变成僵尸进程的机会。
wait函数
只能父进程等待子进程
函数原型 pid_t wait(int status)
#include stdio.h
#include unistd.h
#include stdlib.h
#include sys/types.h
#include sys/wait.h
int main()
{pid_t pid fork();if (pid 0){for (int i 0; i 3; i){printf(children aaa\n);sleep(1);}exit(3);}if (pid 0){printf(parents is ok\n);// 1.获取子进程退出状态int ret;wait(ret);int num WEXITSTATUS(ret);printf(%d\n, ret);// 2.wait(NULL); // 阻塞直到子进程结束再执行下面代码}return 0;
}
waitpid函数 #include stdio.h
#include stdlib.h
#include sys/types.h
#include unistd.h
#include sys/wait.h//父进程等子进程子进程等子子进程
void die(const char *msg)
{perror(msg);exit(1);
}
void child2_do()
{printf(In child2: execute date\n);sleep(5);if (execlp(date, date, NULL) 0){perror(child2 execlp);}
}
void child1_do(pid_t child2, char *argv)
{pid_t pw;do{if (*argv 1){pw waitpid(child2, NULL, 0); // 一直等}else{pw waitpid(child2, NULL, WNOHANG); // 立刻返回}if (pw 0){printf(In child1 process:\nThe child2 process has not exited\n);sleep(1);}} while (pw 0);if (pw child2){printf(Get child2 %d.\n, pw);sleep(5);if (execlp(pwd, pwd, NULL) 0){perror(child1 execlp);}}else{printf(error occured!\n);}
}
void father_do(pid_t child1, char *argv)
{pid_t pw;do{if (*argv 1){pw waitpid(child1, NULL, 0); // 一直等待}else{pw waitpid(child1, NULL, WNOHANG); // 立刻返回}if (pw 0){printf(In father process: \nThe child1 process has not exited.\n);sleep(1);}} while (pw 0);if (pw child1){printf(Get child1 %d.\n, pw);if (execlp(ls, ls, -l, NULL) 0){perror(father execlp);}}else{printf(error occured ! \n);}
}
int main(int argc, char **argv)
{pid_t child1, child2;if (argc 3){printf(Usage: waitpid [0 1] [0 1]\n);exit(1);}child1 fork();if (child1 0){die(child1 fork);}else if (child1 0){child2 fork();if (child2 0){die(child2 fork);}else if (child2 0){child2_do();}else{child1_do(child2, argv[1]);}}else{father_do(child1, argv[2]);}return 0;
}当父进程没有调用waitpid或wait函数来回收子进程的终止状态时子进程的终止状态信息将一直保留在系统的进程表中并使子进程成为僵尸进程。僵尸进程不占用系统资源但是如果产生大量的僵尸进程却没有及时回收可能会导致系统资源被占用完。
通过在父进程中调用waitpid或wait函数父进程会等待子进程的终止并回收其终止状态信息从而防止子进程变成僵尸进程并及时释放子进程占用的资源。这样可以保持系统的正常运行和资源的有效利用。