C++ Getline 并不总是在 Linux 中的多个分叉进程中获得一致

Posted

技术标签:

【中文标题】C++ Getline 并不总是在 Linux 中的多个分叉进程中获得一致【英文标题】:C++ Getline not always getting line in multiple forked processes in Linux 【发布时间】:2017-02-16 05:08:22 【问题描述】:

我正在尝试编写一个程序来创建多个进程,每个进程从控制台中读取一行,然后用它做一些事情。我在使用getline(cin, temp) 时遇到问题,只是有时会读一行。输入缓冲区已经加载了 4 行文本。

编辑:我需要使用 fork,它创建多个进程(而不是线程)才能使用 wait,它等待第一个子进程完成,然后继续。

#include <iostream>
#include <iostream>
#include <string>
#include <cstring>
#include <sstream>
#include <unistd.h>
#include <sys/wait.h>

using namespace std;

int childprog();

int main() 


    pid_t childpid;

    for (int i = 0; i < 4; ++i)
    
        if ((childpid = fork()) == 0) //Child process
        
            childprog();
            return 0;
        
    

    if (childpid != 0) //If Parent
    
        wait(0);
        //Stuff
        return 0;
    


int childprog()

    string temp;
    getline(cin, temp);
    cout << temp << endl; //Actually do other stuff, just here for debugging
    return 0;

虽然它应该打印出来:

string number one
string number two
string number three
string number four

打印出来:

string number one

string number two
string number three

(blank line)
string number one

string number two

在任何可能的位置都有空行。

感谢您的帮助!

【问题讨论】:

你能提供一个minimal reproducible example吗? 好的,完成。该程序完全可运行@πάνταῥεῖ 【参考方案1】:

问题在于每个线程都在访问一个共享资源:getline 和输入缓冲区。有些操作是原子的,有些可以被中断。

这意味着操作的确切时间可能会相互干扰。例如,两个线程检查下一个要读取的行,它们都被告知同一行。然后这是一个“竞争条件”,看哪个线程先读取它,另一个线程得到一个空行。

您需要以某种方式锁定 getline,以便每个线程可以在其他线程潜入并尝试获取一些数据之前读取一行。一个更好的解决方案是避免两个进程处理相同的数据,但假设你不能,那么你可以使用 Mutex。

http://www.thegeekstuff.com/2012/05/c-mutex-examples/

如何使用互斥锁的精简示例:

#include<pthread.h>
#include<unistd.h>

pthread_mutex_t lock;

int childprog()

    // Put the mutex lock and unlock around the minimum amount of code    
    // which needs to be an "atomic operation". While "locked" other 
    // threads won't run this bit of code, so keep it brief. However, 
    // Locking and unlocking is itself an expensive operation, so you
    // should be careful to minimize the number of times it happens

    string temp;

    pthread_mutex_lock(&lock);
    getline(cin, temp);
    pthread_mutex_unlock(&lock);

    cout << temp << endl;

    return 0;


// the rest of your program here

但请注意,在使用互斥体之前还需要初始化一行

pthread_mutex_init(&lock, NULL)

链接的例子是使用 pthread create,而不是 fork

【讨论】:

我需要使用wait,它不适用于线程,只能用于单独的进程。 Mutex 仅适用于线程,因为进程在单独的内存空间中运行。【参考方案2】:

在@JasonLang 发布他的答案并通知我这是访问问题后,我找到了解决方案。我通过简单地将输入缓冲区的读取移动到fork() 之前来纠正它,确保只有一个进程会尝试一次读取它。

我替换了这个:

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

    if ((childpid = fork()) == 0) //Child process
    
        childprog();
        return 0;
    

用这个:

string temp;
for (int i = 0; i < 4; ++i)

    getline(cin, temp);
    if ((childpid = fork()) == 0) //Child process
    
        childprog(temp);
        return 0;
    

还有这个:

int childprog()

    string temp;
    getline(cin, temp);
    cout << temp << endl; //Actually do other stuff, just here for debugging
    return 0;

用这个:

int childprog(string input)

    cout << input << endl; //Actually do other stuff, just here for debugging
    return 0;

【讨论】:

以上是关于C++ Getline 并不总是在 Linux 中的多个分叉进程中获得一致的主要内容,如果未能解决你的问题,请参考以下文章

在 C++ 中确定 getline() 起点

C++ 中的 Getline 和 cin.ignore

C++ 类中的 Getline

C++ 中 cin.getline() 的意外返回

c++ 错误:没有匹配的函数用于从函数内调用“getline”,但在 main 中有效

C++中getline函数的使用