I'm newbie here, so if I have any errors just tell me.
The problem is that I have two processes and I want them to execute concurrently because they take too much time. So I thought to implement a class timer which manage its own boost::asio::io_service and create a thread for this io_service. The code is the following:
timer.hpp
#include <iostream>
#include <string>
#include <functional>
#include <thread>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/asio.hpp>
#include <boost/bind.hpp>
class timer
{
public:
timer(std::function<void(void)> task,
int time)
: io__(),
timer__(io__, boost::posix_time::milliseconds(time)),
repetitive_task__(task),
time_wait__(time)
{
timer__.async_wait(boost::bind(&timer::loop, this));
}
void start()
{
thread__ = std::thread([this](){
io__.run();
});
thread__.join();
}
void loop()
{
repetitive_task__();
timer__.expires_at(timer__.expires_at() + boost::posix_time::milliseconds(time_wait__));
timer__.async_wait(boost::bind(&timer::loop, this));
}
void stop()
{
timer__.cancel();
io__.stop();
}
private:
boost::asio::io_service io__;
boost::asio::deadline_timer timer__;
std::function<void(void)> repetitive_task__;
int time_wait__;
std::thread thread__;
};
For testing it, I have the simplest main I could think:
main.cpp
#include "timer.hpp"
void test1()
{
printf("action1 \n");
}
void test2()
{
printf("action 2 \n");
}
int main(int argc, char* argv[])
{
timer timer1(&test1, 100);
timer timer2(&test2, 50);
timer1.start();
timer2.start();
return 0;
}
And the result is always action1. Never action2.
I've been looking for how to implement timers properly like in this post or in this example of boost, but I still don't understand what I am doing wrong.
Thanks in advance
Related
Before I start, I just was trying something out. I don't know yet if I want to do a big project.
I tried making a TCP Socket Server with Boost as it's much easier than winsock. At least, so I thought, but it doesn't work how I want it. What should happen:
Read configuration
Start TCP Socket Server
Run _acceptor.async_accept
Run io_service.run
Now, I got to the point my socket server works and accepts connections. However, I cannot do user input anymore as io_service.run blocks the rest of my server. I must be doing something wrong.
tcp_listener.h:
#pragma once
#include <boost/asio.hpp>
class tcp_listener
{
public:
tcp_listener(boost::asio::io_service& io_service, std::string ip, short port);
static void start(tcp_listener* ptr);
void start_accepting();
private:
boost::asio::ip::tcp::acceptor _acceptor;
boost::asio::ip::tcp::socket _socket;
};
tcp_listener.cpp:
#include "tcp_listener.h"
#include "logger.h"
#include <boost/asio.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/bind.hpp>
#include <boost/thread.hpp>
#include <memory>
tcp_listener::tcp_listener(boost::asio::io_service& io_service, std::string ip, short port)
: _acceptor(io_service, boost::asio::ip::tcp::endpoint(boost::asio::ip::address_v4::from_string(ip), port)),
_socket(io_service)
{
logger::log_main("Network bound on %s.%d", _acceptor.local_endpoint().address().to_string().data(), _acceptor.local_endpoint().port());
start_accepting();
io_service.run();
}
void tcp_listener::start(tcp_listener* ptr)
{
ptr->start_accepting();
}
void tcp_listener::start_accepting()
{
_acceptor.async_accept(_socket, [this](boost::system::error_code ec)
{
if (!ec)
{
logger::log_main("New connection %s", _socket.remote_endpoint().address().to_string().data());
//std::make_shared<tcp_client>(std::move(socket_))->start_receiving();
}
else
{
_acceptor.close();
}
start_accepting();
});
}
engine.h:
#pragma once
#include "configuration.h"
class engine
{
public:
static void boot();
static void destroy();
static configuration* get_config();
private:
static configuration* config;
};
engine.cpp:
#include "engine.h"
#include "tcp_listener.h"
#include <boost/thread.hpp>
#include <boost/bind.hpp>
configuration* engine::config;
void engine::boot()
{
engine::config = new configuration("config.cnf");
boost::asio::io_service io_service;
tcp_listener& list = tcp_listener(io_service, engine::config->get_value("network.ip"), atoi(engine::config->get_value("network.port").data()));
}
void engine::destroy()
{
delete engine::config;
}
configuration* engine::get_config()
{
return engine::config;
}
Main.cpp:
#include "engine.h"
#include <iostream>
int main()
{
engine::boot();
for (;;)
{
std::string input;
std::cin >> input;
if (input == "exit")
{
engine::destroy();
break;
}
}
return 0;
}
I have searched for more than 5 hours, I tried a million things, nothing work. I tried putting it in a thread, resulting me in an exception. Or the socket server itself didn't work.
The user input is useful to reload certain cached data or close the application or something like that.
This is by design.
Just run the service on a separate thread.
std::thread th([&] { io_service.run(); }); // example
Beware of thread synchronization on shared resources then.
io_service is thread safe (except for special operations like construction, destruction, reset). So, if you must perform tasks that need synchronization it would be easiest to post() it to the service.
As long as you have only 1 thread run-ning the particular io_service instance, you don't need additional synchronization (what is known as a logical or implicit strand¹).
¹ Why do I need strand per connection when using boost::asio?
I'm using Gtkmm and multithreading.
I have a class "NetworkWorker" doig stuffs with the network in a secondary thread.
In this class i want to make many signals which will be handled by my class "MainWindow".
The methods which handle these signals, will edit append text in a TextView.
I have the following code:
NetworkWorker.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);
}
}
MainWindow.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
MainWindow.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());
}
and my 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);
}
These snippetes have been a re-adapted for this question, so maybe some change is incoherent.
When I execute this code, I have the following output:
$> ./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
Can some one help me to resolve this issue ? :)
The issue is you are calling non threadsafe function call (signal callbacks are not threadsafe).
So you need to use something like Glib::signal_idle().connect( sigc::mem_fun(*this, &IdleExample::on_idle) );(or whatever is equivalent to C API call g_idle_add(GCallback func)) from your thread. This function is threadsafe (at least the one from the C API).
See this tutorial for a simplified example.
Never call or signal from different threads when using UI libraries. Usually the APIs are designed to be called from a single thread. This is the single most often made mistake when using UI toolkits.
I want to implement a mechanism that allows me to block program flow until an async operation has completed. (Mostly to be used in unit tests where there is no message loop.)
The code I have creates a thread and waits for a condition notification inside the thread:
#include <chrono>
#include <condition_variable>
#include <iostream>
#include <memory>
#include <mutex>
#include <stdexcept>
#include <thread>
struct Blocker {
Blocker() :
wait_thread([this]() {
std::mutex mtx;
std::unique_lock<std::mutex> lck(mtx);
cond.wait(lck);
})
{
}
void wait() { wait_thread.join(); }
void notify() { cond.notify_one(); }
std::condition_variable cond;
std::thread wait_thread;
};
template<typename Callback>
void async_operation(const Callback & cb) { cb(); }
int main() {
Blocker b;
async_operation([&](){ b.notify(); });
b.wait();
}
The problem is that it often deadlocks because the call to notify occurs before the thread even started. How should I fix this?
#include <mutex>
#include <condition_variable>
struct blocker
{
blocker () : done (false) {}
void
notify ()
{
std::unique_lock<std::mutex> lock (m);
done = true;
c.notify_all ();
}
void
wait ()
{
std::unique_lock<std::mutex> lock (m);
while (!done)
c.wait (lock);
}
bool done;
std::mutex m;
std::condition_variable c;
};
I'm initialized thread on main function when created namspace multithread_init in order to push set_multihthread class to namespace. Why after declared boost::thread it's not matching function for call boost::thread t(smulti.thread)?
#define BOOST_THREAD_USE_LIB
#include <boost/thread.hpp>
#include <boost/thread/thread.hpp>
#include <iostream>
#include <vector>
#include <cstdlib>
#include <ctime>
#include <iostream>
#ifndef MULTITHREAD_INIT_HPP_
#define MULTITHREAD_INIT_HPP_
namespace multithread_init{
class set_multithread{
private:
//t;
public:
void thread(){
for(int i = 0; i < 5; i++){
wait(1);
std::cout<<" thread i value : "<<i<<std::endl;
}
}
void wait(int seconds)
{
boost::this_thread::sleep(boost::posix_time::seconds(seconds));
}
// void multi_case(){
// t.join();
// boost::thread t(thread);
// }
};
}
#endif /* MULTITHREAD_INIT_HPP_ */
main file follow as below.
int main()
{
/*thread */
multithread_init::set_multithread smulti;
boost::thread t(smulti.thread);
t.join();
}
You can't pass a member function that way. You need to bind it to the object
boost::thread t(boost::bind(&multithread_init::set_multithread::thread, &smulti));
I expected the code below to print Hello, world! every 5 seconds, but what happens is that the program pauses for 5 seconds and then prints the message over and over with no subsequent pauses. What am I missing?
#include <iostream>
#include <boost/asio.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
using namespace boost::asio;
using namespace std;
io_service io;
void print(const boost::system::error_code& /*e*/)
{
cout << "Hello, world!\n";
deadline_timer t(io, boost::posix_time::seconds(5));
t.async_wait(print);
}
int main()
{
deadline_timer t(io, boost::posix_time::seconds(5));
t.async_wait(print);
io.run();
return 0;
}
edit to add working code below. thanks guys.
#include <iostream>
#include <boost/bind.hpp>
#include <boost/thread.hpp>
#include <boost/asio.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
using namespace boost::asio;
using namespace std;
class Deadline {
public:
Deadline(deadline_timer &timer) : t(timer) {
wait();
}
void timeout(const boost::system::error_code &e) {
if (e)
return;
cout << "tick" << endl;
wait();
}
void cancel() {
t.cancel();
}
private:
void wait() {
t.expires_from_now(boost::posix_time::seconds(5));
t.async_wait(boost::bind(&Deadline::timeout, this, boost::asio::placeholders::error));
}
deadline_timer &t;
};
class CancelDeadline {
public:
CancelDeadline(Deadline &d) :dl(d) { }
void operator()() {
string cancel;
cin >> cancel;
dl.cancel();
return;
}
private:
Deadline &dl;
};
int main()
{
io_service io;
deadline_timer t(io);
Deadline d(t);
CancelDeadline cd(d);
boost::thread thr1(cd);
io.run();
return 0;
}
You're creating the deadline_timer as a local variable and then immediately exiting the function. This causes the timer to destruct and cancel itself, and calls your function with an error code which you ignore, causing the infinite loop.
Using a single timer object, stored in a member or global variable, should fix this.
#include <iostream>
#include <boost/asio.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
using namespace boost::asio;
using namespace std;
io_service io;
deadline_timer t(io, boost::posix_time::seconds(5));
void print(const boost::system::error_code& /*e*/)
{
cout << "Hello, world!\n";
t.expires_from_now(boost::posix_time::seconds(5));
t.async_wait(print);
}
int main()
{
//deadline_timer t(io, boost::posix_time::seconds(5));
t.async_wait(print);
io.run();
return 0;
}
If you look at the error code, you're getting operation cancelled errors.