首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

在fork中调用函数,在函数中是一个while循环,它应该读取输入,但是,scanf()被完全跳过了

基础概念

在多线程编程中,fork() 是一个系统调用,用于创建一个新的进程。新进程是原进程的一个副本,拥有原进程的数据段、堆栈和代码段的副本。然而,新进程和原进程的进程ID是不同的,并且它们各自独立执行。

scanf() 是一个标准输入函数,用于从标准输入(通常是键盘)读取数据。在多线程或多进程环境中,如果多个线程或进程同时尝试从标准输入读取数据,可能会导致不可预测的行为。

可能的原因

  1. 竞争条件:在 fork() 后,父进程和子进程可能同时运行,导致 scanf() 被跳过。这是因为两个进程共享相同的输入缓冲区,而 scanf() 需要独占访问。
  2. 输入缓冲区问题:如果父进程在 fork() 之前已经读取了一些输入,子进程可能会继承这些输入,导致 scanf() 被跳过。
  3. 信号处理:如果在 fork() 后,父进程或子进程收到了某些信号(如 SIGINT),可能会影响 scanf() 的执行。

解决方案

为了避免这些问题,可以采取以下措施:

  1. 同步机制:使用互斥锁或其他同步机制确保在 fork() 后,只有一个进程能够访问标准输入。
  2. 清理输入缓冲区:在 fork() 之前,清理输入缓冲区,确保子进程不会继承父进程的输入。
  3. 信号处理:在 fork() 后,正确处理可能影响 scanf() 执行的信号。

示例代码

以下是一个简单的示例,展示了如何在 fork() 中安全地使用 scanf()

代码语言:txt
复制
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>

pthread_mutex_t input_mutex = PTHREAD_MUTEX_INITIALIZER;

void* child_process(void* arg) {
    pthread_mutex_lock(&input_mutex);
    printf("Child process: Enter a number: ");
    int num;
    scanf("%d", &num);
    printf("Child process: You entered %d\n", num);
    pthread_mutex_unlock(&input_mutex);
    return NULL;
}

int main() {
    pid_t pid = fork();

    if (pid == 0) {
        // Child process
        child_process(NULL);
    } else if (pid > 0) {
        // Parent process
        pthread_mutex_lock(&input_mutex);
        printf("Parent process: Enter a number: ");
        int num;
        scanf("%d", &num);
        printf("Parent process: You entered %d\n", num);
        pthread_mutex_unlock(&input_mutex);
    } else {
        perror("fork");
        exit(EXIT_FAILURE);
    }

    return 0;
}

参考链接

通过使用互斥锁,可以确保在 fork() 后,父进程和子进程不会同时访问标准输入,从而避免 scanf() 被跳过的问题。

页面内容是否对你有帮助?
有帮助
没帮助

相关·内容

C语言字符串IO

常见的一个错误写法:scanf要把信息拷贝到参数指定的地址上,而此时的参数是一个未初始话的指针,那么可以指向程中的任意的地址,可能会擦写掉程序中的数据和到吗,导致程序中断。...,但是在程序中经常要读取一整行输入,因此gets()可以处理这种情况。...分析: gets函数抛弃\n,puts函数添加\n,fgets函数保留\n,fputs函数不添加\n 第一行输入中:apple pie比fgets函数读入的整行输入短,因此apple pie\n\0被存储在了数组中...然后while循环进入了下一轮迭代,fgets函数继续从输入的剩余中读入数据,一直循环,直到读到tion\n,fgets函数将其存储为tion\n\0,fputs函数打印该字符,并且由于\n进行换行。...分析:scanf第二次读取数据时从上一次调用结束的地方继续读取数据。

4.6K10

论那些在vjduge等oj平台踩过的坑

而且,在oj平台,这种循环输入应该是非常常见的。...(4)注意,循环之后,有一些全局定义的数组可能会被修改过了,那么循环结束一遍之后,要对它进行初始化,更改称为初始值,否则可能出现叠加情况,导致wrong answer!...当然,解决方法可以是在函数体中(或者每次的while循环中)定义新变量,每次重新定义。...=EOF等价)当然是用cin>>好像也是可行的 (12)读取字符串,可以使用scanf(“%s”,str),表示读取整个字符串,同时,不需要加取地址符,而scanf(“%c”,&ch),需要加取地址符号...,表示读取一个字符,注意在读取char型字符串后,最后一个为'\0',最后一个应该为减一strlen(ch)-1 (13)注意就算是你声明double类型变量,你double temp=1/3;结果仍然是

1.4K30
  • 一文带你读懂CC++语言输入输出流与缓存区

    在计算机系统中是指信息从外部输入设备向计算机内部输入,或者从内存向外部输出设备输出的过程。这种输入输出的过程被形象的比喻为“流”。 输入输出 什么是输入输出呢?...原理介绍 当调用输入函数scanf()时,输入函数会将我们输入的数字输入到输入缓冲区,而当我们的输入缓冲区有内容时,再次输入将不会被执行,而是直接跳过执行,将输入缓冲区的内容赋给变量。...函数原型: int getchar(void) ; 说明:当程序调用getchar()函数时,程序就等着用户按键,用户输入的字符被存放在键盘缓冲区中,直到用户按回车为止(回车字符也放在缓冲区中)。...这时函数执行不会让用户输入而是顺序读取缓冲区字符内容。第一个字符用户输入结束后已经读取,所以会从第二个字符开始读    while((c = getchar())!...要理解这一点,之所以你输入的一系列字符被依次读出来,是因为循环的作用使得反复利用getchar在缓冲区里读取字符,而不是ge 最后 很多表面的现象看起来可能不能引起我们的注意,但是当我们注意到细节的时候

    1.2K31

    一文读懂CC++语言输入输出流与缓存区

    在计算机系统中是指信息从外部输入设备向计算机内部输入,或者从内存向外部输出设备输出的过程。这种输入输出的过程被形象的比喻为“流”。 输入输出 什么是输入输出呢?...原理介绍 当调用输入函数scanf()时,输入函数会将我们输入的数字输入到输入缓冲区,而当我们的输入缓冲区有内容时,再次输入将不会被执行,而是直接跳过执行,将输入缓冲区的内容赋给变量。...函数原型: int getchar(void) ; 说明:当程序调用getchar()函数时,程序就等着用户按键,用户输入的字符被存放在键盘缓冲区中,直到用户按回车为止(回车字符也放在缓冲区中)。...这时函数执行不会让用户输入而是顺序读取缓冲区字符内容。第一个字符用户输入结束后已经读取,所以会从第二个字符开始读 while((c = getchar())!...要理解这一点,之所以你输入的一系列字符被依次读出来,是因为循环的作用使得反复利用getchar在缓冲区里读取字符,而不是ge 最后 很多表面的现象看起来可能不能引起我们的注意,但是当我们注意到细节的时候

    1.5K20

    一文带你读懂CC++语言输入输出流与缓存区

    在计算机系统中是指信息从外部输入设备向计算机内部输入,或者从内存向外部输出设备输出的过程。这种输入输出的过程被形象的比喻为“流”。 输入输出 什么是输入输出呢?...原理介绍 当调用输入函数scanf()时,输入函数会将我们输入的数字输入到输入缓冲区,而当我们的输入缓冲区有内容时,再次输入将不会被执行,而是直接跳过执行,将输入缓冲区的内容赋给变量。...函数原型: int getchar(void) ; 说明:当程序调用getchar()函数时,程序就等着用户按键,用户输入的字符被存放在键盘缓冲区中,直到用户按回车为止(回车字符也放在缓冲区中)。...这时函数执行不会让用户输入而是顺序读取缓冲区字符内容。第一个字符用户输入结束后已经读取,所以会从第二个字符开始读 while((c = getchar())!...要理解这一点,之所以你输入的一系列字符被依次读出来,是因为循环的作用使得反复利用getchar在缓冲区里读取字符,而不是ge 最后 很多表面的现象看起来可能不能引起我们的注意,但是当我们注意到细节的时候

    1.9K31

    【C语言新手村】新手任务:认识函数

    C语言中把函数分为两类,一类是库函数,另一类是自定义函数 1.1 库函数 库函数就是在C语言中已经有的一些函数,比如:printf()、scanf()、srtlne...如果所有的操作全都在库函数里面可以直接调用的话,那还要程序员干什么。因此我们也要学会写我们自己的函数。自定义函数和库函数一样,有函数名,返回值类型和函数参数。 但是不一样的是这些都是我们自己来设计。...迭代是将某一个初值设定,不断放入某一个循环体,得到的值成为一个新值再次放入循环体中,通过循环体中的操作,逐步得到我们想要的结果。...一个过程或函数在其定义或说明中有直接或间接 调用自身的 一种方法,它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解, 递归策略 只需少量的程序就可描述出解题过程所需要的多次重复计算...满足上面的条件递归函数不一定正确,但是不满足上面两个条件的函数递归一定是错的 2.3 递归的运用 接受一个整型值(无符号),按照顺序打印它的每一位。

    5400

    【Linux】Linux进程控制>进程创建&&进程终止&&进程等待&&进程程序替换

    1.进程创建 1.1 fork函数 在linux中fork函数时非常重要的函数,它从已存在进程中创建一个新进程。...例如子进程从fork返回后,调用exec函数 1.4 fork调用失败的原因 、 系统中有太多的进程 实际用户的进程数超过了限制 2.进程终止 2.1 进程退出场景 代码运行完毕,结果正确...当进程调用一种exec函数时,该进程的用户空间代码和数据完全被新程序替换,从新程序的启动例程开始执行。...shell建立一个新的进程,然后在那个进程中运行ls程序并等待那个进程结束 然后shell读取新的一行输入,建立一个新的进程,在这个进程中运行程序 并等待这个进程结束。...一个函数可以调用另外一个函数,同时传递给它一些参数。被调用的函数执行一定的操作,然后返回一个值。

    16510

    c语言从入门到实战——函数递归

    函数递归 前言 函数递归是指一个函数直接或间接地调用自身,以解决问题的一种方法。在C语言中,函数递归可以用来计算阶乘、斐波那契数列等数学问题。...递归的基本思想是将问题分解为更简单的子问题,然后组合子问题的解来得到原问题的解。然而,递归需要小心处理终止条件,否则可能导致无限循环。此外,递归可能消耗大量内存,因为它需要存储每个递归调用的状态。...因此,在使用递归时,应仔细考虑其效率和适用性。 1. 递归是什么? 递归是学习C语言函数绕不开的一个话题,那什么是递归呢? 递归其实是一种解决问题的方法,在C语言中,递归就是函数自己调用自己。...1; else return n*Fact(n-1); } Fact函数是可以产生正确的结果,但是在递归函数调用的过程中涉及一些运行时的开销。...我们在 main 函数中调用 jumpFloor 函数,并将结果输出到控制台。当n等于5时,输出结果为:跳上5级台阶共有8种跳法。

    22910

    第五节(信息读写基础)

    第16行是while 循环的开头,只要choice不等于QUIT,程序将不断重复执行while循环体中的语句。 QUIT是一个符号常量,如果用3替换它,程序就不如现在这样清楚明了。...如果用户选择2,将调用printf_ report() 函数(第25行)。 提示: 第16~27行的while循环控制菜单的顶部,至少要运行一次。...scanf()函数以指定的格式从键盘读取数据,并将输入的数据赋值给程序中的一个或多个变量。 printf() 和scanf() 都使用格式字符串描述输入的格式。...scanf()从标准输入流中读取输入字段( inputfield ),并将读取的每个字段都放进一个参数中。 该函数在放置信息时,会将信息转换成格式字符串中相应转换说明的格式。...第二个错误是,在scanf()中answer变量前面没有取址运算符。 第三个错误是,scanf()语句中应该使用%d,而不是%f。因为answer是int类型,不是float类型。

    20520

    Luhn算法检验和验证

    我们可以使用求摸操作符(%)确定奇数和偶数的位置,因为偶数的定义是它能够被2所整除。因此如果表达式位置%2的结果是1,这个位置就是奇数,应该把它扩大一倍。...我们所面临的第一个问题是怎样确定已经到达了标识号的末尾。如果用户输入了一个多位的标识号又按下了Enter键表示结束,并且我们是逐个字符读取输入的,那么在最后一个数字之后所读取的字符是什么呢?...从运行结果中可以看出,10就是我们所寻找的结果,所以我们可以在前面的代码中用一个while循环代替for循环: 1 //处理任意偶数长度的标识号 2 char digit; 3...要穷尽每种可能性,标识号的长度必须是奇数或者偶数。如果我们预先知道长度,就可以知道应该把奇数位的数字或者偶数位的数字扩大一倍。但是,在读取完这个标识号之前,我们并不知道这个信息。...刚开始我还对函数调用和程序中的回车问题有所疑惑,不过在一位朋友的指点下我还是顺利通过了。最重要的是,我对这个算法也有了更深一步的了解与认识。

    1.8K70

    第八节(字符和字符串)

    调用gets()函数时,它将读取第1个换行符(按下Enter键生成)前用户通过键盘输入的所有字符。 该函数会丢弃换行符,在末尾添加一个空字符,并将字符串返回给调用程序。...根据第18行的代码,如果输入一个空行(即,只按下Enter键),该字符串仍被储存,且末尾是空字符。 但是该字符串的长度是0,因此储存在第1个位置上的是空字符。gets()的返回值便指向该位置。...如果第1个字符是空字符(只按下Enter键),关系运算符则返回false,while 循环将终止。 在使用gets()或其他函数通过指针储存数据时,要确保指针指向已分配的空间。...scanf() 函数中的格式字符串告诉该函数如何读取用户输入的信息。 要读取字符串,必须在scanf()的格式字符串中使用%s转换说明。...因此,还需要创建两个变量储存名中的两个部分,或者要求用户在输入时不要添加空格。 正因如此,gets()函数在读取用户输入的字符串方面比scanf()更方便,特别是字符串中包含空格的情况。

    32230

    【C语言】文件操作(1)(文件打开关闭和顺序读写函数的万字笔记)

    它的作用就是从流中获取一个字符,不是应该属于输出吗?...那么为什么在表中它叫字符输入函数呢?   ...这是我们要注意的一点,我们说的输入输出是站在内存的角度思考的,我们从流里面获取了一个字符,对流来说,也就是对文件来说是输出,但是如果站在内存角度思考就会发现,获取的字符存储到内存中了,应该是属于输入,所以我们说的输入输出都是基于内存角度的...所以这里我们还是要利用它的返回值,创建一个while循环,如果fgets没有返回空指针,说明读取到了一行信息,那么我们就把它打印出来,如果返回空指针就结束循环,如下: char arr[20] = {...scanf可以参考文章: 【C语言】printf和scanf函数详解    我们这里也可以顺便说一下它们之间的关系,scanf是从标准输入流读取数据,而fscanf可以从任何流中读取数据,那么fscanf

    13810

    CCPP输入输出函数汇总分析

    .默认的标准输入流即stdio.h中定义的stdin.但是从输入流中读取字符时又 涉及到缓冲的问题,所以并不是在屏幕中敲上一个字符程序就会运行,一般是通过在屏幕上敲上回车键,然后将回车前的字符 串放在缓冲区中...,getchar就是在缓冲区中一个一个的读字符.当然也可以在while循环中指定终止字符,如下面的语句: while ((c = getchar()) !...补充:必须指定用户进程缓冲区的长度n,即buf的大小,此函数从流中一直读到下一个换行符为止,但是不超过n-1个字符,读入的字符被送入用户缓冲区buf中。该缓冲区以null字符结尾。...该函数在C++标准库中已不存在,并被证明是不安全的,因为它不对读取的数据进行长度限制,这可能导致缓冲区溢出。因此,应该使用替代函数,例如fgets()或cin。...原因:在一次函数调用中读、写多个非连续缓冲区,但是这些缓冲区已经用iovec表示好了。

    1.8K20

    计算机小白的成长历程——分支与循环(9)

    第一个输入函数scanf函数——输入字符后通过换行进行确认;之后我们还在探讨while语句时接触了第二个输入函数getchar——读取字符缓冲区的一个字符。接下来我们来探讨一下这两个函数的区别。...这里我们可以理解为就是程序运行后的输入界面,这个输入界面就好比一个生成的空间,我们在界面输入的内容都会储存到这个空间里面,scanf函数会在这个空间里读取空格或者是回车前的所有内容,而getchar函数只能读取这个空间内的一个内容...,这个内容包括空格和换行: 这个光标所在的地方就是输入界面,这时计算机内部会开辟一个空间来存储这个界面里输入的全部内容; 我们在界面输入1234空格abcd回车后,经过打印可以知道,scanf读取了空格前的字符...1234,到getchar时则读取了空格这个字符; 通过这个代码我们可以更加直观的看到getchar是怎么运作的了,一个getchar,它会主动在缓冲区提取一个字符,这个字符包含空格与回车,在scanf...这里咱们就简单点把这个srand理解为初始化rand函数的一个函数,在前面的测试中我们看到了,rand函数在开始运行时,它的值是固定不变的——41,那我们在调用rand函数之前如果调用srand函数的话

    18320

    【C语言系列】函数递归

    ,在这里我们可以看出这个代码一直在执行打印操作,体现了函数递归的现象,但是由于死循环的打印导致了栈溢出的现象。...1.1尾递归尾递归是指一个递归函数在调用自身时,该递归调用是函数的最后一条语句。换句话说,函数在调用自身之后不再执行任何操作,而是直接返回递归调用的结果。这种特殊形式的递归称为尾递归。...:int Fact(int n){ if(n==0) return 1; else return n*Fact(n-1);}Fact函数是可以产生正确的结果,但是在递归函数调用的过程中涉及...在C语言中每⼀次函数调用,都要需要为本次函数调用在栈区申请⼀块内存空间来保存函数调用期间的各种局部变量的值,这块空间被称为运行时堆栈,或者函数栈帧。...函数不返回,函数对应的栈帧空间就⼀直占用,所以如果函数调用中存在递归调用的话,每⼀次递归函数调用都会开辟属于自己的栈帧空间,直到函数递归不再继续,开始回归,才逐层释放栈帧空间。

    10510

    C语言 getchar()原理及易错点解析

    .getchar()系列 1.getchar()工作原理及作用 工作原理:getchar()是stdio.h中的库函数,它的作用是从stdin流中读入一个字符,也就是说,如果stdin有数据的话不用输入它就可以直接读取了...’\n’.要理解这一点,之所以你输入的一系列字符被依次读出来,是因为循环的作用使得反复利用getchar在缓冲区里读取字符,而不是getchar可以读取多个字符,事实上getchar每次只能读取一个字符...问题:如果我们输入a空格bbbbbbbb+回车,那可能需要无数个getchar();来清除缓存,这时应该怎么办?? 解决方法:加入while循环while(getchar()!...原因是,输入的c23其实是c23+换行符,scanf()函数把这个换行符留在了缓存中。...我们需要删除scanf()函数留在缓存中的换行符即可。 在if语句中使用一个break语句,可以在scanf()的返回值不等于2时终止程序,即如果一个或两个输入值不是整数或者遇到文件结尾就终止程序。

    1.4K60

    【Linux】进程概念(上)

    总结,计算机管理硬件/操作系统管理资源 描述起来,用 struct 结构体 组织起来,用链表或其他高效的数据结构 系统调用和库函数概念 在开发角度,操作系统对外会表现为一个整体,但是会暴露自己的部分接口...我们首先需要知道,如果一个函数执行到 return,它的核心工作已经完成了,但是 fork() 之后,代码共享,当代码执行到 return 的时候,return 也是代码,是代码就要进行共享,所以当父进程被调度时...例如我们的代码中出现 scanf()、cin 等,本质是我们从键盘中读取数据,如果我们就是不输入,键盘上面的数据就是没有就绪,也就是说,我们的进程要访问的资源没有就绪,它也就不具备访问条件,该进程的代码也就无法继续向后执行...进程在退出的时候,要有一些退出信息,表明自己把任务完成得怎么样,该信息是由该进程的父进程读取的;这些信息由OS写入到当前退出进程的PCB中,可以允许进程的代码和数据空间被释放,但是不能允许进程的 PCB...如果一个进程进入Z状态了,但是父进程就是不回收它,它的PCB就会一直存在,就有可能会造成内存泄漏! 当它被父进程或者OS读取之后,PCB 状态先被改成X状态,然后才会被完全释放。

    12710

    最通俗易懂地讲解scanf、gets和getchar的区别

    它的作用是从键盘获取且只能获取一个字符。 定义如下: int getchar(void) getchar() 函数是可以接收 空格 的,但是不能接收 回车。...因为 getchar 函数只能输入字符型,所以在输入时遇到 回车键(\n) 才从缓冲区依次提取字符,遇到 空格符不会结束,而是会接收它!!!...也同样是因为它本身只能接收1个字符,所以这个 回车 被留在缓存流中了,而我们这里的程序是遇到 q 才停止,故而程序又循环了一下,相当于输入了一个 回车!!!...输入的书的数量3,留下了一个 回车,如果在这里直接接着使用一个 scanf 的话,就会出错: 因为 回车 会留在缓存流中,并被下一个函数 get 读取到,从而扰乱了本来的数据读取,继而出现了非预期结果...3、总结 scanf 忽略行开头的所有空格,并以各种格式化进行数据输入,直到遇到 空格、回车 结束输入,不接收 空格 和 回车,留在缓存区中; getchar 只读取一个字符,包括 空格 但是不包括

    6.1K31
    领券