繁体   English   中英

如何将数据写入标准输入以供等待标准输入输入的单独线程使用?

[英]How to write data to stdin to be consumed by a separate thread waiting on input from stdin?

我试图从与主线程不同的线程中从stdin读取一些数据。 主线程应该能够通过写入stdin来与该等待线程进行通信,但是当我运行测试代码(包含在下面)时,什么都没有发生,只是消息(测试代码中的“ do_some_work”)直接打印在终端上而不是从等待线程输出。

我尝试了SO上列出的几种解决方案,但没有成功。 我的代码模仿了以下SO问题中的一种解决方案,它本身可以很好地工作,但是当与我的read_stdin_thread结合使用时,效果却并非如此。

是否可以在Linux中将数据写入自己的标准输入

#include <unistd.h>
#include <string>
#include <iostream>
#include <sstream>
#include <thread>

bool terminate_read = true;

void readStdin() {

    static const int INPUT_BUF_SIZE = 1024;
    char buf[INPUT_BUF_SIZE];

    while (terminate_read) {
        fd_set readfds;
        struct timeval tv;
        int data;

        FD_ZERO(&readfds);
        FD_SET(STDIN_FILENO, &readfds);
        tv.tv_sec=2;
        tv.tv_usec=0;
        int ret = select(16, &readfds, 0, 0, &tv);
        if (ret == 0) {
            continue;
        } else if (ret == -1) {
            perror("select");
            continue;
        }
        data=FD_ISSET(STDIN_FILENO, &readfds);
        if (data>0) {
            int bytes = read(STDIN_FILENO,buf,INPUT_BUF_SIZE);
            if (bytes == -1) {
                perror("input poll: read");
                continue;
            }
            if (bytes) {
                std::cout << "Execute: " << buf << std::endl;
                if (strncmp(buf, "quit", 4)==0) {
                    std::cout << "quitting reading from stdin." << std::endl;
                    break;
                }
                else {
                    continue;
                }
            }
        }
    }
}

int main() {
    std::thread threadReadStdin([] () {
        readStdin();
    });

    usleep(1000000);
    std::stringstream msg;
    msg << "do_some_work" << std::endl;
    auto s = msg.str();
    write(STDIN_FILENO, s.c_str(), s.size());
    usleep(1000000);

    terminate_read = false;
    threadReadStdin.join();

    return 0;
}

一个代码片段说明了如何写入标准输入,然后再由threadReadStdin读取,这将非常有帮助。

在此先感谢!

编辑:

我在这里忘记提及的一件事是,readStdin()中的代码是第三方代码,并且发生的任何形式的通信都必须遵守其条款。

另外,我很容易就能将std :: cin和std :: cout重定向到fstream或stringstream。 问题是,当我写入重定向的cin缓冲区时,在读取线程上什么也没有真正出现。

EDIT2:

这是一个单进程应用程序,无法生成。

如果要使用管道在同一程序中的不同线程之间进行通信,则不应尝试使用stdinstdout 相反,只需使用pipe功能来创建自己的管道。 我将逐步指导您!

打开频道

让我们创建一个辅助函数,以使用pipe打开通道。 此函数通过引用获取两个整数-读取端和写入端。 它尝试打开管道,如果不能打开,则会显示错误。

#include <unistd.h>
#include <cstdio>
#include <thread>
#include <string>

void open_channel(int& read_fd, int& write_fd) {
    int vals[2];
    int errc = pipe(vals); 
    if(errc) {
        fputs("Bad pipe", stderr); 
        read_fd = -1;
        write_fd = -1; 
    } else {
        read_fd = vals[0];
        write_fd = vals[1]; 
    }
}

写一条消息

接下来,我们定义一个函数来编写消息。 该函数以lambda形式给出,因此我们可以将其直接传递给线程。

auto write_message = [](int write_fd, std::string message) {
    ssize_t amnt_written = write(write_fd, message.data(), message.size());
    if(amnt_written != message.size()) {
        fputs("Bad write", stderr); 
    }
    close(write_fd); 
}; 

阅读讯息

我们还应该提供读取消息的功能。 阅读消息将在其他线程上完成。 此lambda读取一种类型的消息1000字节,并将其打印为标准输出。

auto read_message = [](int read_fd) {
    constexpr int buffer_size = 1000; 
    char buffer[buffer_size + 1]; 
    ssize_t amnt_read; 
    do {
        amnt_read = read(read_fd, &buffer[0], buffer_size);
        buffer[amnt_read] = 0; 
        fwrite(buffer, 1, amnt_read, stdout); 
    } while(amnt_read > 0); 
};

主要方法

最后,我们可以编写main方法。 它打开通道,在一个线程上写入消息,然后在另一线程上读取消息。

int main() {
    int read_fd;
    int write_fd;
    open_channel(read_fd, write_fd); 

    std::thread write_thread(
        write_message, write_fd, "Hello, world!"); 
    std::thread read_thread(
        read_message, read_fd); 
    write_thread.join(); 
    read_thread.join(); 
}

似乎我在@Jorge Perez,@ Remy Lebeau和@Kamil Cuk的非常有建设性的回应的帮助下迷失了答案。 该解决方案基于@Jorge Perez的非常有用的代码。 为了简洁起见,我没有包括整个代码,但是一部分来自我发布的代码,而很大一部分来自@Jorge Perez的代码。

我所做的就是使用管道的方法,并使用dup将管道fd替换为STDIN_FILENO。 以下链接确实有帮助:

https://en.wikipedia.org/wiki/Dup_(system_call)

考虑到我在生产环境代码中的约束,对于您的输入是hack还是足够好的方法/解决方案,我非常感谢您的投入。

int main() {
    int read_fd;
    int write_fd;

    open_channel(read_fd, write_fd); 

    close(STDIN_FILENO);
    if(dup(read_fd) == -1)
        return -1;

    std::thread write_thread(write_message, write_fd, "Whatsup?"); 
    std::thread threadReadStdin([] () {
        readStdin();
    });

    write_thread.join(); 
    threadReadStdin.join();

    return 0;
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM