关于Redis在windows上运行及fork函数问题
Redis在将数据库进行持久化操作时,需要fork一个进程,但是windows并不支持fork,导致在持久化操作期间,Redis必须阻塞所有的客户端直至持久化操作完成。微软的一些工程师花费时间在解决在windows环境下Redis无法进行后台保存,并决定使用线程代替fork产生的子进程来对硬盘执行写操作,但这给分支只提供了源码并没有提供预编译二进制文件,并且微软不保证它能否用于生产环境。
上面这段是我摘抄于黄健宏老师翻译的《Redis实战》这本书的。
下面我解释一下fork函数的一些问题
- fork函数
 
fork()函数通过系统调用创建一个与原来进程几乎完全相同的进程。
下面的侧重点在于fork与递归的区分。
创建fork_test1.c
我们可以touch fork_test1.c,
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
int main(int argc, char **argv) {
    pid_t pid = fork();
    if (pid==0) {
        printf("我是父进程,pid是: %d\n",getpid());
        exit(0);
    } else if (pid > 0) {
        printf("我是子进程,pid是: %d\n",getpid());
    } else {
        printf("Error while forking\n");
        exit(EXIT_FAILURE);
    }
    return 0;
}
使用cc fork_test.c进行编译。
执行可执行文件a.out
./a.out
我是子进程,pid是: 1492
我是父进程,pid是: 1493
为什么没有死递归
观察执行结果会发现的子进程的返回值是0,至于为什么是0,暂不讨论。
我好奇的是程序为什么没有进行死递归,因为我认为程序会复制一份重新运行。
经过一番查阅后发现,因为,fork是复制父进程的数据段,堆,栈等,因此,父进程与子进程执行程序位置也是相同的,函数fork完之后,父进程与子进程同时执行到到了第一个if语句,因此子进程并不会重新执行fork()函数,因此没有递归。
验证一下
我们可以touch fork_test2.c,
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
int main(int argc, char **argv) {
    printf("abcd");
    pid_t pid = fork();
    if (pid==0) {
        printf("我是父进程,pid是: %d\n",getpid());
        exit(0);
    } else if (pid > 0) {
        printf("我是子进程,pid是: %d\n",getpid());
    } else {
        printf("Error while forking\n");
        exit(EXIT_FAILURE);
    }
    return 0;
}
编译
cc fork_test2.c
执行
./a.out
你会发现程序没有死递归。
上面难道是错的
但是观察结果你会发现为什么"abcd"输出了两次,不是两个进程都执行到了第一个if语句吗?为什么子进程也会输出。
上面讲的并没有错,你应该注意到,fork()的复制就包括输出缓冲区。
而程序并不会立即把输出的数据显示到屏幕上,而是先存储在输出缓冲区中,当满足一定条件时才显示出来。
输出缓冲区类型
缓冲区的类型:
缓冲区 分为三种类型:全缓冲、行缓冲和不带缓冲。
1、全缓冲
在这种情况下,当填满标准I/O缓存后才进行行实际I/O操作。全缓冲的典型代表是对磁盘文件的读写。
2、行缓冲
在这种情况下,当在输入和输出中遇到换行符时,执行真正的I/O操作。这时,我们输入的字符先存放在缓冲区,等按下回车键换行时才进行实际的I/O操作。典型代表是键盘输入数据。
3、不带缓冲
也就是不进行缓冲,标准出错情况stderr是典型代表,这使得出错信息可以直接尽快地显示出来。
所以,因为我们的fork_test2.c没有触发任何刷新缓冲区的操作,因此复制的时候子进程的缓冲区中也会有"abcd",所以就会输出两次。
如何触发缓冲区刷新
那么我们就触发缓冲区刷新的操作,如何触发呢?
1、遇到\n
2、程序结束
3、遇到输入语句
4、当缓冲区满时
5、fflush(stdout) 手动刷新
我们尝试用第一种方法修改代码,
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
int main(int argc, char **argv) {
    printf("abcd\n");
    pid_t pid = fork();
    if (pid==0) {
        printf("我是父进程,pid是: %d\n",getpid());
        exit(0);
    } else if (pid > 0) {
        printf("我是子进程,pid是: %d\n",getpid());
    } else {
        printf("Error while forking\n");
        exit(EXIT_FAILURE);
    }
    return 0;
}
拨云见日
然后重新编译运行,你会发现"abcd"只会被输出一次,子进程复制的输出缓冲区为空。到此解释了fork·与递归的一些问题。
如果有什么问题大家可以在下面留言。
关于Redis在windows上运行及fork函数问题的更多相关文章
- redis 在windows上运行
		
参考自:https://github.com/ServiceStack/redis-windows 1.用vagrant 运行redis的最后版本 1.1在windows上安装vagrant http ...
 - 大数据高性能数据库Redis在Windows上的使用教程
		
Redis学习笔记----Redis在windows上的安装配置和使用 Redis简介 redis是一个key-value存储系统.和Memcached类似,它支持存储的value类型相对更多,包括s ...
 - 使 IIS 6.0 可以在 64 位 Windows 上运行 32 位应用程序 试图加载格式不正确的程序。
		
原文 使 IIS 6.0 可以在 64 位 Windows 上运行 32 位应用程序 试图加载格式不正确的程序. win7 64位操作系统上边运行IIS网站应用的时候,提示错误"试图加载格式 ...
 - 如何实现在Windows上运行Linux程序,附示例代码
		
微软在去年发布了Bash On Windows, 这项技术允许在Windows上运行Linux程序, 我相信已经有很多文章解释过Bash On Windows的原理, 而今天的这篇文章将会讲解如何自己 ...
 - 在Windows上运行Linux
		
在Windows上运行Linux 之前了解过一些适用于linux的Windows子系统,最近又听人提起,于是在自己的Windows 10专业版上安装了一个Ubuntu.运行起来还真方便,以后在wind ...
 - Docker在Linux/Windows上运行NetCore文章系列
		
Windows系列 因为Window很简单,VS提供界面化配置,所以只写了一篇文章 Docker在Windows上运行NetCore系列(一)使用命令控制台运行.NetCore控制台应用 Linux( ...
 - Docker在Windows上运行NetCore系列(一)使用命令控制台运行.NetCore控制台应用
		
系列文章:https://www.cnblogs.com/alunchen/p/10121379.html 本篇文章操作系统信息 Windows:Window 10 Visual Studio:201 ...
 - 如何使用Cygwin在Windows上运行OpenSSH SSHD服务器
		
记录几款非常有趣, 但不怎么耳熟的软件: Cygwin 是可以安装 OpenSSH server 和 client 的, Mosh 也可以, 这对于 Linux 用户而言就非常方便了. 如何使用Cyg ...
 - 电脑出现“损坏的图像”窗口提示dll没有被指定在Windows上运行如何解决
		
电脑中出现了无法运行应用程序的情况,弹出一个“***.exe - 损坏的图像”的窗口,上面提示“***.dll没有被指定在Windows上运行……”,如果我们遇到这样的问题,应该要如何解决呢? 1.我 ...
 
随机推荐
- script标签crossorigin属性及同源策略和跨域方法
			
首先介绍(同源策略) 同源策略是浏览器最核心且基本的安全约定,要求协议.域名.端口都相同为同源,如果非同源时请求数据浏览器会在控制台抛出跨域异常错误,同源策略是浏览器的行为,即使客户端请求发送了,服务 ...
 - php7.1 安装amqp扩展
			
在php开发中使用rabbitmq消息队列时,需要安装PHP扩展amqp,安装步骤如下: 直接使用pecl进行amqp扩展的安装, /usr/local/php/bin/pecl install am ...
 - JS:null
			
null:它表示一个变量是空的或未知的. 看例子! var a = null; var b = 1; var c = "a"; var d; var e = "" ...
 - 重学ES系列之新型数据结构Map应用
			
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
 - 宝塔Linux面板安装教程
			
宝塔Linux面板安装教程 安装要求: 内存:512M以上,推荐768M以上(纯面板约占系统60M内存) 硬盘:300M以上可用硬盘空间(纯面板约占20M磁盘空间) 系统:CentOS 7.1+ (U ...
 - Android Studio 的初次使用
			
记录我第一次使用Android Studio时遇到的问题以及一些简单的笔记. 我所使用的是Android Studio 2.2版本 遇到的问题 创建一个Hello World!项目无疑是相当简单的,我 ...
 - 爬虫(14) - Scrapy-Redis分布式爬虫(1) | 详解
			
1.什么是Scrapy-Redis Scrapy-Redis是scrapy框架基于redis的分布式组件,是scrapy的扩展:分布式爬虫将多台主机组合起来,共同完成一个爬取任务,快速高效地提高爬取效 ...
 - 【docker专栏2】CentOS操作系统安装DockerCE
			
目录 一.前置要求 二.更新软件源信息 三.安装 Docker-CE 四.卸载Docker CE 为大家介绍在CentOS操作系统中安装docker的过程,linux其他发行版本安装docker方法可 ...
 - Linux挂载webdav
			
Docker挂载webdav(推荐): docker run -itd \ --name mydav \ --device /dev/fuse \ --cap-add SYS_ADMIN \ --se ...
 - Docker详解(上)
			
Docker 学习 Docker概述 Docker安装 Docker命令 镜像命令 容器命令 操作命令 ... Docker镜像 容器数据卷 DockerFile Docker网络原理 IDEA整合D ...