两个进程printf在c中的一个终端重叠

Posted

技术标签:

【中文标题】两个进程printf在c中的一个终端重叠【英文标题】:two processes printf overlapping in one terminal in c 【发布时间】:2021-10-05 11:31:40 【问题描述】:

我需要编写一个创建多线程进程的程序,该程序正在创建另一个多线程进程,而我遇到的问题是在两个进程的运行中有一些时间点在打印到终端时相互重叠。

例如:

//father process
printf("I'm father process\n");

//child process
fprintf(stderr,"I'm child process\n");

结果:

I'I'mm fachtheril proprcesscoess

无论如何我可以确保不会发生这种情况吗?

如果有帮助,父进程和子进程将通过匿名管道连接。


添加编辑:

我在父进程中创建容器(线程)的主线程,每个容器(线程)都有自己的 ID,并宣布该容器开始工作。 然后线程本身需要使用管道并将其 id 发送给子进程。当子进程通过管道获得 id 时,他宣布 id 到达。但在此之前,子进程会初始化另一个调用起重机的线程,目的不同,它们也会在创建时宣布。

*每个线程都有自己的信号量。 *在每次宣布线程进入休眠 5-3000 毫秒后。

所以问题只是在父进程的主线程开始创建容器和子进程中的主线程创建起重机时才发生的问题,打印重叠或开始一个句子停止启动另一个并返回到第一个。虽然所有的打印都在一行中有 /n 和命令。

我将尝试添加我的代码的最小可重现示例:

父进程:

主线程:

    /* create Input the pipe  */
if (!CreatePipe(&InputReadHandle, &InputWriteHandle, &sa, 0)) 
    fprintf(stderr, "Main::Create Pipe Failed @ father\n");
    return 1;

/* create Output the pipe */
if (!CreatePipe(&OutputReadHandle, &OutputWriteHandle, &sa, 0)) 
    fprintf(stderr, "Main::Create Pipe Failed @ father\n");
    return 1;


/* establish the START_INFO structure for the child process */
GetStartupInfo(&si);
si.hStdError = GetStdHandle(STD_OUTPUT_HANDLE);

/* redirect the standard input/output to the read end of the pipe */
si.hStdOutput = OutputWriteHandle;
si.hStdInput = InputReadHandle;
si.dwFlags = STARTF_USESTDHANDLES;

/* we do not want the child to inherit the write end of the pipe */
SetHandleInformation(InputWriteHandle, HANDLE_FLAG_INHERIT, 0);


wcscpy(ProcessName, L"..\\..\\child\\Debug\\child.exe");


/* create the child process */
if (!CreateProcess(NULL,
    ProcessName,
    NULL,
    NULL,
    TRUE, /* inherit handles */
    0,
    NULL,
    NULL,
    &si,
    &pi))

    fprintf(stderr, "Main::Process Creation Failed @ father\n");
    return -1;



/* father now wants to write to the pipe */
if (!WriteFile(InputWriteHandle, &numOfVessels, BUFFER_SIZE, &written, NULL))
    fprintf(stderr, "Main::Error writing to pipe\n");

。 . .

// Create all vessel Threads. Report if Error occurred!
for (int i = 0; i < numOfVessels; i++)

    vesselsID[i] = i+1;
    vesselsSem[i] = CreateSemaphore(NULL, 0, 1, NULL);
    if (vesselsSem[i] == NULL)
    
        fprintf(stderr, "Main::Unexpected Error in Vessles Semaphore %d Creation\n", i);
        return FALSE;
    
    vesselsArr[i] = CreateThread(NULL, 0, Vessel, &vesselsID[i], 0, &ThreadId);
    if (vesselsArr[i] == NULL) 
        fprintf(stderr,"Main::Unexpected Error in Thread %d Creation\n", i);
        exit(1);
    


//wait to all thread(vessel) to finish.
WaitForMultipleObjects(numOfVessels, vesselsArr, TRUE, INFINITE);

血管螺纹:

DWORD WINAPI Vessel(PVOID Param)

int id = *(int*)Param;

printf("%s Vessel %d - starts sailing @ father\n", getTime(),id);

Sleep(random());//Simulate a process Sailing

//sent to child .
    // make sure only one vessel at the time enter to the canal.
WaitForSingleObject(mutex, INFINITE);

printf( "%s Vessel %d - senting to child @father\n", getTime(), id);

Sleep(random());//Simulate a process  

//send the id vessel to child port through pipe.
if (!WriteFile(InputWriteHandle, &id, BUFFER_SIZE, &written, NULL))
    fprintf(stderr, "Error writing to pipe @ father\n");

// the vessel has been sent and can be release .
if (!ReleaseMutex(mutex))

    fprintf(stderr, " Unexpected error mutex.V()\n");


子进程: 主线程:

    for (int i = 0; i < numOfCrane; i++)

    adtArr[i].craneID = i + 1;

    craneSem[i] = CreateSemaphore(NULL, 0, 1, NULL);
    if (craneSem[i] == NULL)
    
        fprintf(stderr, "Main::Unexpected Error in Vessles Semaphore %d Creation @child\n", i);
        return FALSE;
    


    craneArr[i] = CreateThread(NULL, 0, Crane, &adtArr[i].craneID, 0, &ThreadId);
    if (craneArr[i] == NULL) 
        fprintf(stderr, "main::Unexpected Error in Thread %d Creation @child \n", i);
        exit(1);
    
    adtArr[i].cargo = 0;
    adtArr[i].vesselID = 0;

    
    fprintf(stderr, "%s Crane %d created @child  \n", getTime(), adtArr[i].craneID);

。 . .

//read the vessel from pipe
for (int i = 0; i < numOfVessels; i++)
       
        //if readfile is empty then it's wait.
        if (ReadFile(ReadHandle, buffer, BUFFER_SIZE, &read, NULL))
        
            vesselsID[(*buffer) - 1] = (*buffer);
            vesselsSem[(*buffer) - 1] = CreateSemaphore(NULL, 0, 1, NULL);
            if (vesselsSem[(*buffer) - 1] == NULL)
            
                fprintf(stderr, "Main::Unexpected Error in Vessles Semaphore %d Creation\n", (*buffer));
                return FALSE;
            
            vesselsArr[(*buffer) - 1] = CreateThread(NULL, 0, Vessel, &vesselsID[(*buffer) - 1], 0, &ThreadId);
            if (vesselsArr[(*buffer) - 1] == NULL) 
                fprintf(stderr, "main::Unexpected Error in Thread %d Creation \n", (*buffer));
                exit(1);
            
            barrier[i] = (*buffer); // need to write abinormal behavier

            
            fprintf(stderr, "%s Vessel %d - arrirved @ child \n", getTime(), *buffer);
            Sleep(random());
        
    

我希望我能很好地解释自己。

【问题讨论】:

相关:***.com/q/467938 请注意,stderrstdio 是两个不同的文件句柄,因此您的两个输出之间没有协调并不一定让我感到惊讶。如果您对两个进程使用相同的文件句柄,它可能会达到您的预期。 但是如果我尝试在子进程的 stdio 中使用它根本不会打印到控制台 从您显示的调用看来,您显示的输出不太可能。默认情况下,printf 到终端通常是行缓冲的。单个字符不会一次发送几个,即使您在多个printf 调用中一次传递几个字符。当看到换行符或缓冲区已满时,它们将立即全部发送。所以我怀疑这个问题比你在帖子中展示或描述的要多。也就是说,要协调两个进程的输出,您需要在它们之间进行协调,使用某种形式的进程间通信。你们班最近学了什么? 请告诉我们minimal reproducible example。您的示例输出缺少 d。 【参考方案1】:

最简单的解决方案是添加换行符“\n”。

//father process
printf("I'm father process\n");

//child process
fprintf(stderr,"I'm child process\n");

这会阻止你的输出,但它不会阻止哪个先出现,父母的输出或孩子的输出。如果您希望该行为同步,则需要更复杂的同步(如共享内存和互斥锁)。

【讨论】:

以上是关于两个进程printf在c中的一个终端重叠的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Linux 终端中有两个正在运行的进程? (Linux 命令)

在另一个进程中访问共享内存缓冲区

print、printf、println的区别

print、printf、println的区别

print、printf、println的区别

如何在Python中让两个print函数的输出打印在一行内