如何通过阻止读取Gtk3中的另一个线程中的数据来检索数据?

时间:2018-09-21 04:17:48

标签: multithreading gtk3

我有一个库,只公开了对流数据的阻塞ReadRead函数。现在我需要读取数据并在GTK3 GUI中显示。因此,我使用事务通道从运行Read到GUI线程的线程传递数据,然后通过g_idle_add读取var。显然这是错误的。应用程序导致CPU繁忙。正确的方法是什么?

伪代码:

idleAdd PRIORITY_DEFAULT_IDLE $ do
  readTChan chan >>= \case
    Nothing -> return SOURCE_CONTINUE
    Just data -> show_data_in_textview data
forkIO $ loop $ do
  theRead >>= writeTChan chan

1 个答案:

答案 0 :(得分:4)

IOChannelpipe一起使用:

#include <gtkmm.h>
#include <string>
#include <iostream>
#include <thread>
#include <chrono>
#include <fcntl.h>
using namespace std::chrono_literals;

int main(int argc, char* argv[])
{
    auto Application = Gtk::Application::create();
    Gtk::Window window;
    Gtk::ScrolledWindow scrolled;
    Gtk::Box box(Gtk::ORIENTATION_VERTICAL) ;

    window.add(scrolled);
    scrolled.add(box);
    window.show_all();

    int pipeDescriptors[2];
    pipe(pipeDescriptors);
    bool keepAlive = true;
    auto channel = Glib::IOChannel::create_from_fd(pipeDescriptors[0]);
    channel->set_flags(Glib::IO_FLAG_NONBLOCK| Glib::IO_FLAG_IS_READABLE);
    Glib::signal_io().connect([&](Glib::IOCondition ioCondition)->bool
    {
        std::cerr<<"condition: "<<ioCondition<<std::endl;
        Glib::ustring fifoData;
        channel->read_line(fifoData);
        std::cerr<<"read: "<<fifoData<<std::endl;
        auto label = new Gtk::Label(fifoData);
        box.add(*label);
        box.show_all();
        return true;
    }, channel, Glib::IO_IN);

    auto thread = std::thread([&]{
        while(keepAlive)
        {
            std::string buffer = "theRead()\n";
            //it can also be char*. Newline is important because of read_line in the handler

            write(pipeDescriptors[1], buffer.c_str(), buffer.size());
            std::this_thread::sleep_for(1s);
        }
    });

    window.signal_delete_event().connect([&](GdkEventAny* any_event)->bool{
        keepAlive=false;
        thread.join();
        close(pipeDescriptors[1]); //let's start with input
        close(pipeDescriptors[0]);
        return false;
    });

    return Application->run(window);
}