gpt4 book ai didi

c++ - 从线程安全地发出信号并将其连接到小部件

转载 作者:行者123 更新时间:2023-11-27 23:06:24 28 4
gpt4 key购买 nike

我正在使用 Gtkmm 和多线程。

我有一个“NetworkWorker”类在辅助线程中处理网络。在这个类中,我想发出许多信号,这些信号将由我的类“MainWindow”处理。

处理这些信号的方法将在 TextView 中编辑追加文本。

我有以下代码:

网络 worker .h

#ifndef         NETWORKWORKER_H_
# define NETWORKWORKER_H_

# include <sigc++/sigc++.h>
# include <glibmm/threads.h>
# include <string>

class NetworkWorker
{
public:
NetworkWorker();
~NetworkWorker();

void start();
void stop();

sigc::signal<void, std::string&>& signal_data_received();

private:
void run();

sigc::signal<void, std::string&> m_signal_data_received;

Glib::Threads::Thread* m_thread;
Glib::Threads::Mutex m_mutex;
bool m_stop;
};

#endif

NetworkWorker.c

#include        <cstdlib>
#include <glibmm/timer.h>
#include <glibmm/threads.h>
#include <iostream>
#include <sigc++/sigc++.h>

#include "NetworkWorker.h"

NetworkWorker::NetworkWorker() :
m_thread(NULL), m_stop(false)
{

}

NetworkWorker::~NetworkWorker()
{
stop();
}

void NetworkWorker::start()
{
if (!m_thread)
m_thread = Glib::Threads::Thread::create(sigc::mem_fun(*this, &NetworkWorker::run));
}

void NetworkWorker::stop()
{
{
Glib::Threads::Mutex::Lock lock(m_mutex);
m_stop = true;
}

if (m_thread)
m_thread->join();
}

sigc::signal<void, std::string&>& NetworkWorker::signal_data_received()
{
return m_signal_data_received;
}

void NetworkWorker::run()
{
while (true)
{
{
Glib::Threads::Mutex::Lock lock(m_mutex);
if (m_stop)
break;
}
Glib::usleep(5000);
std::cout << "Thread" << std::endl;
std::string* str = new std::string("MyData");
m_signal_data_received.emit(*str);
}
}

主窗口.h

#ifndef         MAIN_WINDOW_H_
# define MAIN_WINDOW_H_

# include <gtkmm/textview.h>
# include <gtkmm/window.h>
# include <string>

class MainWindow : public Gtk::Window
{
public:
MainWindow();
~MainWindow();

void appendText(const std::string& str);

private:
Gtk::TextView m_text_view;
};

#endif

主窗口.c

#include        <gtkmm/notebook.h>
#include <gtkmm/widget.h>
#include <iostream>
#include <string>

#include "MainWindow.h"

MainWindow::MainWindow()
{
set_title("My App");
set_default_size(800, 600);
add(m_text_view);
}

MainWindow::~MainWindow()
{

}

void MainWindow::appendText(const std::string& str)
{
std::string final_text = str + "\n";
Glib::RefPtr<Gtk::TextBuffer> buffer = m_text_view.get_buffer();
Gtk::TextBuffer::iterator it = buffer->end();
buffer->insert(it, final_text);
Glib::RefPtr<Gtk::Adjustment> adj = m_text_view.get_vadjustment();
adj->set_value(adj->get_upper() - adj->get_page_size());
}

和我的 main.cpp

#include        <cstdlib>
#include <gtkmm/main.h>
#include <iostream>
#include <string>

#include "MainWindow.h"
#include "NetworkWorker.h"

void recv(const std::string& str)
{
std::cout << str << std::endl;
}

int main(int argc, char **argv)
{
Gtk::Main app(Gtk::Main(argc, argv));
MainWindow main_window;
NetworkWorker network_worker;

main_window.show_all();

network_worker.signal_data_received().connect(sigc::ptr_fun(&recv));
network_worker.signal_data_received().connect(sigc::mem_fun(main_window, &MainWindow::appendText));
network_worker.start();

Gtk::Main::run(main_window);
return (EXIT_SUCCESS);
}

这些片段已经针对这个问题进行了重新改编,所以可能有些变化是不连贯的。

当我执行这段代码时,我得到以下输出:

$> ./client 
Thread
MyData
Thread
MyData
[...]
Thread
MyData
Thread
MyData
(client:5596): Gtk-CRITICAL **: gtk_text_layout_real_invalidate: assertion 'layout->wrap_loop_count == 0' failed
Thread
MyData
Thread
MyData
[...]
Thread
MyData
Thread
MyData
[1] 5596 segmentation fault (core dumped) ./client

有人可以帮我解决这个问题吗? :)

最佳答案

问题是您正在调用 线程安全函数调用(信号回调不是线程安全的)。

因此,您需要使用类似 Glib::signal_idle().connect( sigc::mem_fun(*this, &IdleExample::on_idle) );(或任何等效于 C API 调用的东西g_idle_add(GCallback func)) 来自你的线程。此函数线程安全的(至少是来自 C API 的函数)。

查看此 tutorial一个简化的例子。


使用 UI 库时,切勿从不同的线程调用或发出信号。通常,API 设计为从单个 线程调用。这是使用 UI 工具包时最常犯的错误。

关于c++ - 从线程安全地发出信号并将其连接到小部件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23281110/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com