main.c main.o/main.obj main/main.exe 编译 连接 程序运行; 两步: gcc/g++ -c main.c/main.cpp -> main.o gcc/g++ -o main main.o -> main(可执行文件) 一步: gcc -o main mian.c -> main 工程文件: rm *.o gcc -c 文件名 各种源代码文件->.o :n 定于哪一行
静态库(运行一次该函数,编译时包含到主函数里,有多份,升级时,即使库取消,也可编译,编译时),动态库(运行函数只有一份)时执行在运行时将方法加载到内存中,升级将老的库替换为新库 如何做库: 库在user/lib(用户自定义库),/lib(系统库) 现将.c编译成.o 静态库:打包:ar crv libXXX.a .o文件(做好了) 如何使用: 库名,路径,(标准路径不需要具体路径-l库名) -L路径. -l库名(优先使用动态库) gcc -o test test.c 库的路径和名字-lXXX 动态库: gcc -shared -fPIC -o libXXX.so max.c add.c 等文件 //动态库创建 1. 先编译成.o文件 2. 运行时从标准库中运行,将动态库放到标准库中。
8.17 debug 有调试信息 release 无调试信息 #include<unistd.h>//linux中的系统程序 制作工程: 1. all:可执行文件名main 2. main: main.o XX.o LL.o ..... gcc -o main main.o XX.o LL.o....(首行按 tab键,形成目标文件的命令) 3. main.o: main.c//依赖文件 gcc -c main.c 4 XX.o: XX.c//依赖文件 gcc -c XX.c 5 LL.o: LL.c gcc -c LL.c 6 clean clean: -rf(清除文件,不对于出错的文件报告) rm -rf *.o main(清除中间文件) install: 注:
将可执行文件拷贝到/usr/bin,则编译完后,输入可执行文件名bin存的是命令如ls who ..。 没写目标文件来源规则,也可进行编译,用cc编译 make -n 输出要操作的步骤而不具体执行(makefile文件) make -f mk (clean)
8.21
进程:运行的程序:运行,就绪,堵塞(I/O堵塞) PCB(进程控制块):用结构体编写《记录进程的信息》,PID(整型值) 操作系统:串行处理,批处理,多道程序设计(内存管理,进程管理),分时系统(时间片轮转法),实时系统(在一定时间内响应,控制系统中) 内存管理: CPU<-内存(程序加载到内存中)<-磁盘,利用总线连接。把作业分成页,产生页表,记录程序在内存中的位置,虚拟内存(磁盘里,内存不足,将程序的一部分加载到内存中,用的时候在建立虚拟内存),缺页中断(内存中没有该页)。 Linux:system(“/bin/ps”);产生新进程(system(“/test”) fork(),产生一个子进程,程序和父类一样,现将父类PCB拷贝一份,连在父类PCB后面,该进程处于阻塞状态,赋值实体程序在内存中,处于就绪。共享的不需要拷贝, exit(0)退出程序 sleep(time); 打印信息:加回车\n,缓冲区放满,程序结束刷缓冲区。 _exit(0),跳过刷缓冲区。 fflush();刷缓冲区 getpid();子进程getppid()父进程;shell(fork进程);物理地址不在同一块空间,
917 父进程比子进程快,init 是他的父进程id=1。 wait 父进程处于阻塞状态。获取信息子进程信息。 僵尸进程;子进程先于父进程,没有用wait获取子进程的信息。 重新启动一个进程,execl(),原来程序的id和现在启动的程序一样。从新的程序的main开始。 每个进程都是由fork +exec()(启动一个新的程序)产生的 echo $PATH str=hhjdh -> echo $str export str//str 设置为环境变量 进程控制: fork产生一个子进程产生失败原因为: 当系统进程总数已达到系统规定的最大数,用户可建立的进程数已达到系统规定的最大数 时, errno 中含有出错代码 EAGAIN。 exec:功能:如果 exec 调用成功, 调用进程将被覆盖,然后从新程序的入口开始执行。这样就产生了一个新的进程,但是它 的进程标识符与调用进程相同,通过用一个新的程序覆盖原内存空间,来实现进程的转变 ,exec 没有建立一个与调用进程并发的新进程, 而是用新进程取代了原来的进程,即新进程的ID和调用进程的ID一样。 系统调用 exec 和 fork()联合起来为程序员提供了强有力的功能。我们可以先用 fork()建 立子进程,然后在子进程中使用 exec,这样就实现了父进程运行一个与其不同的子进程,并 且父进程不会被覆盖。 将文件位置指针定位在当前位置。 文件位置指针已移到第10个字节。 fork() 父进程打开的文件,在子进程中也实用,两个进程公用该文件指针,当子进程移动该指针时,相当于父进程也移动了该指针。 exec() 启动一个新的进程,在原进程中打开的文件在新进程中也是打开的。 已打开的文件描述符可以通过exec被传进新的程序(主函数的参数),并且这个文件指针参数不会被exec调用改变。 exit()除了停止进程的运行外,它还有一些其它作用,其中最重要的是,它将关闭所有 已打开的文件。如果父进程因执行了 wait()调用而处于睡眠状态,那么子进程执行 exit()会 重新启动父进程运行。_exit()函数可以停止系统内部的缓冲区的清除工作。
close()会让数据写回磁盘,并释放该文件所占用的资源。
传统方式下,Fork创建一个子进程,并为子进程创建一个父进程地址空间的拷贝。然而,由于许多子进程在创建之后通常马上会执行系统调用exec,所以父进程地址空间的复制可能没有必要,从而造成效率和内存的极大浪费。因此,就产生了一种称为“写时复制”的技术。
现在是写时复制
写 时复制允许子进程与父进程在开始时共享同一页面。但这些页面被标记为“写时复制”,即如果任何一个进程需要对页进行写操作,就会创建这个共享页的拷贝。例 如,假设子进程试图修改含有部分栈的页,且操作系统能够识别出该页为写时复制页,则操作系统就会创建该页的一个拷贝,并将它映射的子进程的地址空间里。这 样,子进程修改的就是其复制的页,而不是父进程的页。采用写时复制技术,只有被进程所修改的页才会复制,而所有非修改的页可为父进程和子进程共享。注意, 并不是所有的页都标记为写时复制,只有可能修改的页才需要标记为写时复制,对不能修改的页,如代码页,可谓父进程和子进程所共享。
Vfork(Virtual memory fork)
Vfork不 同于写时复制的fork。对于vfork,父进程会挂起,以确保子进程先运行。子进程使用父进程的地址空间。由于vfork不使用写时复制,因此如果子进 程修改地址空间的任何页,这些修改在父进程重启时都是可见的。所以,vfork必须小心使用,以确保子进程不会修改父进程的地址空间。Vfork主要用于 在进程创建后立即调用exec的情况,这样既没有出现复制页,也不会修改父进程的地址空间,所以是一种很有效的进程创建方法。
父子进程的区别:
进程ID不同,两个进程具有不同的父进程,子进程的父进程ID是创建他的进程ID,父进程的父进程则不变,子进程的tms_utime,tms_stme,tms_cutime,tms_ustime均设置为0.
父进程设置的文件锁不会被子进程继承,子进程的未处理的闹钟被消除,子进程未处理的信号机被处理为空集。
文件共享: 这种共享文件的方式使得父子进程对同一件文件使用了一个文件偏移量,1.一个进程fork了一个子进程,然后等待子进程终止,父子都向文件写东西,若父进程输出已重定向,南无子进程写到该文件时,它将更新与父进程共享的该文件的该偏移量,当父进程等待子进程时,子进程写到文件,而当子进程终止时,父进程也写到该文件,添加到子进程所写的数据之后。