操作系统:Linux,语言:纯C
我将继续学习一般的C编程,在特殊情况下将学习UNIX下的C编程。
printf()
使用fork()
调用后,我检测到该函数的奇怪行为(对我而言)。
码
#include <stdio.h>
#include <system.h>
int main()
{
int pid;
printf( "Hello, my pid is %d", getpid() );
pid = fork();
if( pid == 0 )
{
printf( "\nI was forked! :D" );
sleep( 3 );
}
else
{
waitpid( pid, NULL, 0 );
printf( "\n%d was forked!", pid );
}
return 0;
}
输出量
Hello, my pid is 1111
I was forked! :DHello, my pid is 1111
2222 was forked!
为什么第二个“ Hello”字符串出现在孩子的输出中?
是的,这恰恰是父母在开始时打印的内容,并带有父母的pid
。
但!如果我们\n
在每个字符串的末尾放置一个字符,则会得到预期的输出:
#include <stdio.h>
#include <system.h>
int main()
{
int pid;
printf( "Hello, my pid is %d\n", getpid() ); // SIC!!
pid = fork();
if( pid == 0 )
{
printf( "I was forked! :D" ); // removed the '\n', no matter
sleep( 3 );
}
else
{
waitpid( pid, NULL, 0 );
printf( "\n%d was forked!", pid );
}
return 0;
}
输出 :
Hello, my pid is 1111
I was forked! :D
2222 was forked!
为什么会发生?这是正确的行为还是错误?
我注意到这<system.h>
是一个非标准头文件;我将其替换为<unistd.h>
干净地编译的代码。
当程序的输出进入终端(屏幕)时,它是行缓冲的。当程序的输出进入管道时,将被完全缓冲。您可以通过标准C函数setvbuf()
以及_IOFBF
(完全缓冲),_IOLBF
(行缓冲)和_IONBF
(无缓冲)模式来控制缓冲模式。
您可以通过将程序的输出传递到,在修改后的程序中进行演示cat
。即使printf()
字符串末尾有换行符,您也会看到重复信息。如果直接将其发送到终端,则只会看到很多信息。
这个故事的寓意是要小心fflush(0);
在分叉之前调用所有I / O缓冲区。
按要求进行逐行分析(大括号等已删除-标记编辑器已删除了前导空格):
printf( "Hello, my pid is %d", getpid() );
pid = fork();
if( pid == 0 )
printf( "\nI was forked! :D" );
sleep( 3 );
else
waitpid( pid, NULL, 0 );
printf( "\n%d was forked!", pid );
分析:
pid == 0
并执行第4和5行;父对象的值为非零pid
(两个进程之间的几个差异之一-从getpid()
和返回的值getppid()
是另外两个)。父级现在通常通过main的结尾处的返回退出,并且清除了剩余数据;由于末尾仍然没有换行符,因此光标位置在感叹号之后,并且shell提示出现在同一行上。
我看到的是:
Osiris-2 JL: ./xx
Hello, my pid is 37290
I was forked! :DHello, my pid is 37290
37291 was forked!Osiris-2 JL:
Osiris-2 JL:
PID号不同-但整体外观清晰。在printf()
语句的末尾添加换行符(这很快成为标准做法)会极大地改变输出:
#include <stdio.h>
#include <unistd.h>
int main()
{
int pid;
printf( "Hello, my pid is %d\n", getpid() );
pid = fork();
if( pid == 0 )
printf( "I was forked! :D %d\n", getpid() );
else
{
waitpid( pid, NULL, 0 );
printf( "%d was forked!\n", pid );
}
return 0;
}
我现在得到:
Osiris-2 JL: ./xx
Hello, my pid is 37589
I was forked! :D 37590
37590 was forked!
Osiris-2 JL: ./xx | cat
Hello, my pid is 37594
I was forked! :D 37596
Hello, my pid is 37594
37596 was forked!
Osiris-2 JL:
请注意,当输出到达终端时,它是行缓冲的,因此“
Hello”行出现在之前,fork()
并且只有一个副本。当输出通过管道传递到时cat
,它已被完全缓冲,因此在fork()
和两个进程的要刷新的缓冲区中都有“
Hello”行之前,什么都没有出现。
问题内容: 我做常规的事情: 叉子() 子文件中的execvp(cmd,) 如果execvp因找不到cmd而失败,如何在父进程中注意到此错误? 问题答案: 著名的自管技巧可以适用于这一目的。 这是一个完整的程序。 工作原理: 创建一个管道,并创建write端点:成功执行an时,它将自动关闭。 在孩子中,尝试。如果成功,我们将不再具有控制权,但管道已关闭。如果失败,则将失败代码写入管道并退出。 在父
我被CompletableFuture异常处理卡住了。 我的逻辑是发送电子邮件并保存此操作的状态。如果发送电子邮件抛出异常,我需要用异常消息保存状态。 处理器类目前有此代码。它工作正常,但对我来说并不优雅。我们如何摆脱用于在阶段之间共享状态的错误本地字段? 看起来句柄方法应该会有所帮助,但它返回可完成未来的可完成未来
问题内容: 我一直想在Google上找到这四个之间的区别,我希望这方面会有大量的信息,但是这四个调用之间确实没有任何可靠的比较。 我着手尝试汇编一下这些系统调用之间的区别的基本概况,这就是我得到的。所有这些信息是否正确/我是否缺少任何重要信息? :fork调用基本上是对当前过程进行复制,几乎在所有方面都相同(例如,并非在某些实现中都复制了所有内容,例如,在某些实现中资源有限,但其想法是创建尽可能近
问题内容: 我在Linux上有两个进程A和B。我想与进程B共享进程A的文件描述符,现在我只是将其序列化为a 并将其传递给参数,但这是行不通的。 Ac看起来像这样: BC看起来像这样: 但这是行不通的,我也不明白为什么不这样做。我该如何进行这项工作?如果它的工作原理,它是经过共享父母和孩子之间的文件描述符的最佳解决方案和一个? 更新资料 该问题与我提出的问题无关,这是由@OliCharleswort
描述 (Description) 此函数将通过FORMAT指定的格式解释的LIST值打印到当前输出文件句柄或FILEHANDLE指定的值。 有效地相当于打印FILEHANDLE sprintf(FORMAT, LIST) 如果不需要特定的输出格式,可以使用print代替printf。 以下是已接受的格式转换列表。 Sr.No. 格式和结果 1 %% 百分号 2 %c 具有给定ASCII码的字符 3
printf(格式化输出数据) 相关函数 scanf,snprintf 表头文件 #include<stdio.h> 定义函数 int printf(const char * format,.............); 函数说明 printf()会根据参数format字符串来转换并格式化数据,然后将结 果写出到标准输出设备,直到出现字符串结束('\0')为止。参数 format字符串可包含下列三