操作系统:Linux,语言:纯 C
我正在学习一般的 C 编程,以及特殊情况下的 UNIX 下的 C 编程。
在使用 fork() 调用后,我检测到 printf() 函数有一个奇怪的(对我而言)行为。
代码
#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);在 fork 之前清空所有 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() 的返回值是另外两个)。parent现在通过main结束时的return正常退出,残留数据被flush;由于末尾仍然没有换行符,所以光标位置在感叹号之后,并且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”行。
关于c - "fork()"后printf异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2530663/
我正在尝试测试是否存在表单。我是Rails新手。我的new.html.erb_spec.rb文件的内容是:require'spec_helper'describe"messages/new.html.erb"doit"shouldrendertheform"dorender'/messages/new.html.erb'reponse.shouldhave_form_putting_to(@message)with_submit_buttonendendView本身,new.html.erb,有代码:当我运行rspec时,它失败了:1)messages/new.html.erbshou
我在从html页面生成PDF时遇到问题。我正在使用PDFkit。在安装它的过程中,我注意到我需要wkhtmltopdf。所以我也安装了它。我做了PDFkit的文档所说的一切......现在我在尝试加载PDF时遇到了这个错误。这里是错误:commandfailed:"/usr/local/bin/wkhtmltopdf""--margin-right""0.75in""--page-size""Letter""--margin-top""0.75in""--margin-bottom""0.75in""--encoding""UTF-8""--margin-left""0.75in""-
为了将Cucumber用于命令行脚本,我按照提供的说明安装了arubagem。它在我的Gemfile中,我可以验证是否安装了正确的版本并且我已经包含了require'aruba/cucumber'在'features/env.rb'中为了确保它能正常工作,我写了以下场景:@announceScenario:Testingcucumber/arubaGivenablankslateThentheoutputfrom"ls-la"shouldcontain"drw"假设事情应该失败。它确实失败了,但失败的原因是错误的:@announceScenario:Testingcucumber/ar
在MRIRuby中我可以这样做:deftransferinternal_server=self.init_serverpid=forkdointernal_server.runend#Maketheserverprocessrunindependently.Process.detach(pid)internal_client=self.init_client#Dootherstuffwithconnectingtointernal_server...internal_client.post('somedata')ensure#KillserverProcess.kill('KILL',
我遵循MichaelHartl的“RubyonRails教程:学习Web开发”,并创建了检查用户名和电子邮件长度有效性的测试(名称最多50个字符,电子邮件最多255个字符)。test/helpers/application_helper_test.rb的内容是:require'test_helper'classApplicationHelperTest在运行bundleexecraketest时,所有测试都通过了,但我看到以下消息在最后被标记为错误:ERROR["test_full_title_helper",ApplicationHelperTest,1.820016791]test
我正在学习Rails,并阅读了关于乐观锁的内容。我已将类型为integer的lock_version列添加到我的articles表中。但现在每当我第一次尝试更新记录时,我都会收到StaleObjectError异常。这是我的迁移:classAddLockVersionToArticle当我尝试通过Rails控制台更新文章时:article=Article.first=>#我这样做:article.title="newtitle"article.save我明白了:(0.3ms)begintransaction(0.3ms)UPDATE"articles"SET"title"='dwdwd
我正在尝试从Postgresql表(table1)中获取数据,该表由另一个相关表(property)的字段(table2)过滤。在纯SQL中,我会这样编写查询:SELECT*FROMtable1JOINtable2USING(table2_id)WHEREtable2.propertyLIKE'query%'这工作正常:scope:my_scope,->(query){includes(:table2).where("table2.property":query)}但我真正需要的是使用LIKE运算符进行过滤,而不是严格相等。然而,这是行不通的:scope:my_scope,->(que
我正在尝试编写一个将文件上传到AWS并公开该文件的Ruby脚本。我做了以下事情:s3=Aws::S3::Resource.new(credentials:Aws::Credentials.new(KEY,SECRET),region:'us-west-2')obj=s3.bucket('stg-db').object('key')obj.upload_file(filename)这似乎工作正常,除了该文件不是公开可用的,而且我无法获得它的公共(public)URL。但是当我登录到S3时,我可以正常查看我的文件。为了使其公开可用,我将最后一行更改为obj.upload_file(file
在Cooper的书BeginningRuby中,第166页有一个我无法重现的示例。classSongincludeComparableattr_accessor:lengthdef(other)@lengthother.lengthenddefinitialize(song_name,length)@song_name=song_name@length=lengthendenda=Song.new('Rockaroundtheclock',143)b=Song.new('BohemianRhapsody',544)c=Song.new('MinuteWaltz',60)a.betwee
当我尝试安装Ruby时遇到此错误。我试过查看this和this但无济于事➜~brewinstallrubyWarning:YouareusingOSX10.12.Wedonotprovidesupportforthispre-releaseversion.Youmayencounterbuildfailuresorotherbreakages.Pleasecreatepull-requestsinsteadoffilingissues.==>Installingdependenciesforruby:readline,libyaml,makedepend==>Installingrub