04父子进程循环、父子信号处理、文件IO小知识

一、父子进程循环

image

//--------------------------------------------------------------------------------
(i)ngx_master_process_cycle()        //创建子进程等一系列动作
(i)|---ngx_setproctitle()            //设置进程标题    
(i)|---ngx_start_worker_processes()  //创建worker子进程=====
(i)|---|---for (i = 0; i < threadnums; i++)   //master进程在走这个循环,来创建若干个子进程
(i)|---|---|---ngx_spawn_process(i,"worker process");
(i)|---|---|---|---pid = fork(); //分叉,从原来的一个master进程(一个叉),
(i)|---|---|---|---//分成两个叉(原有的master进程,以及一个新fork()出来的worker进程
(i)|---|---|---|---//只有子进程这个分叉才会执行ngx_worker_process_cycle()
(i)|---|---|---|---ngx_worker_process_cycle(inum,pprocname);  //子进程分叉
(i)|---|---|---|---|---ngx_worker_process_init();
(i)|---|---|---|---|---|---sigemptyset(&set);  
(i)|---|---|---|---|---|---sigprocmask(SIG_SETMASK, &set, NULL); //允许接收所有信号
(i)|---|---|---|---|---ngx_setproctitle(pprocname); //重新为子进程设置标题为worker process
(i)|---|---|---|---|---for ( ;; ) {}. ....  //子进程开始在这里不断的死循环
(i)|---sigemptyset(&set); //信号屏蔽字为空,表示不屏蔽任何信号
(i)|---for ( ;; ) {}.       //父进程[master进程]会一直在这里循环
//--------------------------------------------------------------------------------

二、父子信号处理

ngx_init_signals() 初始化信号函数
位置:signal/ngx_signal.cxx

PS:关于父进程的循环内容
父进程是管理进程,是由信号进行驱动的,所以对于在没有系统信号来的时候,应该要处于休眠状态
sigsuspend(&set);
解释:
在常态下,信号是解除屏蔽的,当来一个信号的时候,会去执行该信号的处理函数,不仅如此,该函数还会使之前的屏蔽状态继续生效,这样做的目的是为了不打断当前信号的处理函数的执行。
在printf的前面,sigsuspend()的后面,之间,会执行来信号的那个信号处理函数
image

PS:关于行缓存
printf()函数不加\n无法及时输出的解释,printf末尾不加\n就无法及时的将信息显示到屏幕 ,这是因为 行缓存[windows上一般没有,类Unix上才有],需要输出的数据不直接显示到终端,而是首先缓存到某个地方,当遇到行刷新表指或者该缓存已满的情况下,才会把缓存的数据显示到终端设备;ANSI C 中定义\n认为是行刷新标记,所以,printf函数没有带\n是不会自动刷新输出流,直至行缓存被填满才显示到屏幕上;
所以用printf的时候,
----1.注意末尾要用\n;
----2.或者: fflush(stdout); //刷新标准输出缓冲区,把输出缓冲区里的东西打印到标准输出设备上,则printf里的东西会立即输出;
----3.或者: setvbuf(stdout,NULL,_IONBF,0); //这个函数. 直接将printf缓冲区禁止, printf就直接输出了。
标准I/O函数,后边还会讲到。

三、文件IO知识

write()函数思考

  1. 多个进程写一个文件,可能会出现数据覆盖,混乱等情况(进程之间存在父子关系时,在同时写一个文件时,是不会混乱的,原因是,这样关系的进程们打开同一文件的文件描述符是相同的)
  2. ngx_log.fd = open((const char *)plogname, O_WRONLY|O_APPEND|O_CREAT,0644);//O_APPEND这个标记能够保证多个进程操作同一个文件时不会相互覆盖;
  3. 内核wirte()写入时是原子操作;
    所以 不会造成日志文件混乱。

掉电导致write()的数据丢失破解法
a)直接I/O:直接访问物理磁盘:
----O_DIRECT:在打开文件的时候绕过内核缓冲区。用posix_memalign(以后讲)
b)open文件时用O_SYNC选项:
----同步选项【把数据直接同步到磁盘】,只针对write函数有效,使每次write()操作等待物理I/O操作的完成;
c)缓存同步: 尽量保证缓存数据和写道磁盘上的数据一致;
----sync(void):将所有修改过的块缓冲区排入写队列;然后返回,并不等待实际写磁盘操作结束,数据是否写入磁盘并没有保证;
----fsync(int fd):将fd对应的文件的块缓冲区立即写入磁盘,并等待实际写磁盘操作结束返回;
----fdatasync(int fd):类似于fsync,但只影响文件的数据部分。而fsync不一样,fsync除数据外,还会同步更新文件属性;

fwrite和write有啥区别;
----fwrite(): 是标准I/O库一般在stdio.h文件,C语言提供的。中间还夹了一层(如图所示)
----write(): 系统调用;操作系统提供的。

posted @ 2022-03-04 20:35  豪崽_ZH  阅读(154)  评论(0)    收藏  举报