添加while循环后printf不输出(一个“\n”引发的血案)

消息队列使用+关于printf缓冲区的问题

简单来讲

printf是一个行缓冲函数,先写到缓冲区,满足条件后,才将缓冲区刷到对应文件中,刷缓冲区的条件如下:

1 缓冲区填满

2 写入的字符中有"\n" "\r"

3 调用fflush手动刷新缓冲区

4 调用scanf要从缓冲区中读取数据时,也会将缓冲区内的数据刷新

当然,执行printf的进程或线程结束后,会自动调用fflush刷新缓冲区。
缓冲区大小1024字节。
重点只有这些,后面的可以不用看(* ̄︶ ̄)

故事的开头

某次用C在写一个简单的消息队列使用时,出现了一个问题,服务端在接收消息时使用while循环使其可以一直接收,但是发现循环中的printf不起作用了????

上代码

//msgcom.h
#include <errno.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdio.h>
#define MSGKEY 1234
struct msgtype
{
  long mtype;
  int text;
};
//req.c
#include "msgcom.h"
void main()
{
  struct msgtype buf;
  int qid,pid;
  qid = msgget(MSGKEY,IPC_CREAT|0666);
  buf.mtype=1;
  printf("Please input a number:");
  scanf("%d",&buf.text);
  msgsnd(qid,&buf,sizeof(buf.text),IPC_NOWAIT|04000);
  msgrcv(qid,&buf,sizeof(buf.text),2,MSG_NOERROR);
  printf("Request received a message from server: %d\n",buf.text);
}
//serv.c
#include "msgcom.h"
int main()
{
  struct msgtype buf;
  int qid;
  if ((qid=msgget(MSGKEY,IPC_CREAT|0666))==-1)
  return (-1);
  while (1)
 {
   msgrcv(qid,&buf,sizeof(buf.text),1,MSG_NOERROR);
   printf("Server receive a request from process: %d\n",buf.text);
   buf.mtype=2;
   buf.text=buf.text+1;
   msgsnd(qid,&buf,sizeof(buf.text),IPC_NOWAIT|04000);
 }
}

分析一下

代码看着是不是没有什么问题,实际上也确实没有什么大问题。但是!如果把serv.c中

printf("Server receive a request from process: %d\n",buf.text);

替换成

printf("Server receive a request from process: %d",buf.text);

问题就来了
req.c运行毫无问题,serv.c却怎么也不输出。
看过前面的缓冲区的知识当然一眼看穿,但是无奈当时没想到啊。

debug的心路历程

第一阶段:先前前后后都printf一下吧,发现什么也没有发生,没有任何输出。
第二阶段:msgrcv是会阻塞的,把msgrcv去掉试试,emmmmm,疯狂输出
所以是因为msgrcv阻塞了,所以后面的语句没有执行?并不,不然为什么第一阶段放在msgrcv之前的printf也没有输出,而且req.c正常输出了serv.c返回的数据?
第三阶段:req.c是正常的,看看有什么区别啊。第一眼,while循环。好的,循环去掉,正常了。

那么,为什么呢?

捋捋思路,首先,这样的执行看不出问题,从req那边看是正常的,这边没有输出,也看不出异常

  while (1)
 {
   msgrcv(qid,&buf,sizeof(buf.text),1,MSG_NOERROR);
  // printf("Server receive a request from process: %d",buf.text);
   buf.mtype=2;
   buf.text=buf.text+1;
   msgsnd(qid,&buf,sizeof(buf.text),IPC_NOWAIT|04000);
 }

下面这样,疯狂输出,这个很好理解

 while (1)
 {
  // msgrcv(qid,&buf,sizeof(buf.text),1,MSG_NOERROR);
   printf("Server receive a request from process: %d",buf.text);
   buf.mtype=2;
   buf.text=buf.text+1;
   msgsnd(qid,&buf,sizeof(buf.text),IPC_NOWAIT|04000);
 }

下面这样,没有问题

// while (1)
// {
   msgrcv(qid,&buf,sizeof(buf.text),1,MSG_NOERROR);
   printf("Server receive a request from process: %d",buf.text);
   buf.mtype=2;
   buf.text=buf.text+1;
   msgsnd(qid,&buf,sizeof(buf.text),IPC_NOWAIT|04000);
// }

所以,问题代码精简为

 while (1)
 {
   msgrcv(qid,&buf,sizeof(buf.text),1,MSG_NOERROR);
   printf("Server receive a request from process: %d",buf.text);
 }

三者不能共存?逗呢
似乎陷入僵局。
但是!前面有一个很重要的线索,就是在msgrcv甚至while之前加printf,也不输出。
像这样

 printf("test");
 while (1)
 {
   msgrcv(qid,&buf,sizeof(buf.text),1,MSG_NOERROR);
   printf("Server receive a request from process: %d",buf.text);
 }

test也不输出,没道理啊。不应该执行到printf(“test”)的时候马上输出吗?没有立即输出,没有立即输出……缓冲了?缓冲区?
想到这个,上网搜索printf+缓冲区,看到文章最开头的知识点,OK,破案了。

printf没有加"\n",不刷新,不输出。

缓冲区满?似乎1024字节,一次算你五十个,你得不停尝试20次,才有可能看到结果(尝试了一下,二十四次之后就一次性输出了(* ̄︶ ̄))。
去掉msgrcv,不阻塞,while疯狂循环,缓冲区迅速填满输出,所以看上去正常输出了,其实不是一个一个输出的,是一次输一堆。
去掉while循环,一次执行,程序结束之后自动刷新,所以输出。

结案。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值