Factory for threads in C++ - c++

I am currently trying to create a sort of "factory" pattern in a class, whose instances should be Threads that have their own certain operation procedure. I have currently declared a global variable isFinished in order to end the operation of the worker thread, however, somehow the operation does not stop after the variable state is changed, and the worker thread does not do the std::thread::join() operation in order to finish working. I am new to threads, and in C++ in general and I don't really know what is wrong so any help would be greatly appreciated.
Here is the code:
\\main.cpp
#include <iostream>
#include <thread>
#include <atomic>
#include "Sender.h"
int main()
{
isFinished = false; //set false for worker thread
Sender mSender; //Create thread object for worker
std::cin.get(); //Trigger by pressing enter
isFinished = true; //exit worker while loop
mSender.join(); //wait for the worker thread to finish execution
}
\\sender.cpp
#include <iostream>
#include <thread>
#include <atomic>
#include "Sender.h"
void Sender::SenderWorkflow()
{
while (!isFinished)
{
std::cout << "Working... \n";
}
}
\\sender.h
#include <iostream>
#include <thread>
#include <atomic>
static std::atomic<bool> isFinished;
class Sender {
public:
std::thread worker;
Sender()
: worker(&Sender::SenderWorkflow, this)
{
}
void SenderWorkflow();
void join() {
worker.join(); \\std::thread::join()
}
};

The problem is that you are using a static variable in the global scope. static in a namespace scope is used to hide the variable or function in the object file so that the linker can't see it while linking another object file for another cpp file. In practice static is used only inside the cpp file itself. Since you declared it inside the header each translation unit that includes it will get a different instance of the variable because the linker can't see the same variable across objects file. To solve this :
1- move the declaration of the static variable to the cpp file and make an accessor function in the header file:
\\sender.h
#include <atomic>
const std::atomic<bool>& checkIsFinished();
void setFinished();
\\sender.cpp
static std::atomic<bool> isFinished;
const std::atomic<bool>& checkIsFinished() { return isFinished; }
void setFinished() { isFinished = true; }
2- or use inline variable (since c++17) in the header file:
\\sender.h
#include <atomic>
inline std::atomic<bool> isFinished;
3 - or better and the correct design : make the variable local as member of the class, the less global variables the better !
\\sender.h
#include <atomic>
class Sender {
public:
std::thread worker;
Sender()
: worker(&Sender::SenderWorkflow, this)
{
}
void SenderWorkflow();
void join() {
isFinished = true;
worker.join(); \\std::thread::join()
}
private:
std::atomic<bool> isFinished = false;
};

Related

C++: Application crashes with abort() on logging function

here is my code which is run on windows:
Log.h
#include <iostream>
#include <sstream>
#include <fstream>
#include <shared_mutex>
#include <thread>
#include <iomanip>
class Log {
public:
static std::ofstream myfile;
static std::shared_mutex m_smutex;
static bool isLogEnabled();
static void close() {
Log::myfile.close();
}
template< typename... Args >
static void debug(const char* format, Args... args) {
std::unique_lock<std::shared_mutex> lock(Log::m_smutex);
if (isLogEnabled()) {
if (!Log::myfile.is_open()) {
Log::myfile.open("C:\\tmp\\log.txt", std::ios_base::app);
}
...
Log::myfile.close();
}
else {
if (Log::myfile.is_open()) {
Log::myfile.flush();
Log::myfile.close();
}
}
}
};
You can see I've deleted most of the code(...) because I narrowed down the problem.
Log.cpp
#include <Windows.h>
#include "Log.h"
std::ofstream LogLine::myfile;
std::shared_mutex LogLine::m_smutex;
bool LogLine::isLogEnabled() {
CHAR regeditPath[MAX_PATH] = { 0 };
CHAR variable[] = "DEBUG_LOGS";
GetEnvironmentVariableA(variable, regeditPath, MAX_PATH);
return GetLastError() == ERROR_ENVVAR_NOT_FOUND ? false : true;
}
The process needs to be run always, that's why I open and close the file everytime I log something. I want to be able to delete logs even when the process is still running. Maybe this is silly because there might be a flag which would allow me to delete the logs while file is open by some process.
Example usage:
Log::debug("little test %d", 10);
As you can see I use mutex because I want to call debug function from different threads. The problem is that after some time I get error code Abort() has been called but I can't understand why.
P.S
I created this code inside custom Credential Provider to enable debugging, but I'm checking in the internet and it seems like nobody is using logging there. Is it because it's forbidden? Maybe this is reason of the crash?

Reference to object with std::async

I have a small solution in visual studio 2012. The solution consists of two projects (Scanner and TestApp), Scanner is a dll and TestApp is a small application using the dll.
I would like a function in the dll to run in a thread and to report its result back via a queue to the TestApp.
To test this I wrote a minimal application, but depending on how I launch the thread I get different results and I would like to understand why.
The Scanner.h file looks like this:
#pragma once
#include <iostream>
#include <string>
#include <stdint.h>
#include <atomic>
#include <future>
#include <thread>
#include "version.h"
#include "threadsafe_queue.h"
#include "capture_data.h"
#include "process_data.h"
#ifdef SCANNER_EXPORTS
#define SCANNER_API __declspec(dllexport)
#else
#define SCANNER_API __declspec(dllimport)
#endif
class Scanner
{
public:
static SCANNER_API void run();
static SCANNER_API void stop();
};
Scanner.cpp:
#include "stdafx.h"
#include "Scanner.h"
std::vector<std::future<int>> my_futures;
void Scanner::run()
{
CaptureData capture_data(1234);
auto t = std::async(std::launch::async, &CaptureData::get_data, capture_data);
my_futures.push_back(std::move(t));
}
void Scanner::stop()
{
for(int n=0; n<my_futures.size(); n++) {
auto e = std::move(my_futures.back());
e.get();
my_futures.pop_back();
}
}
The class CaptureData is defined in capture_data.h and capture_data.cpp.
capture_data.h:
#pragma once
#include <atomic>
#include <thread>
#include "iq_data.h"
#include "threadsafe_queue.h"
class CaptureData
{
public:
CaptureData(double freq_start);
void configure();
void get_data();
private:
double m_test;
};
capture_data.cpp
#include "stdafx.h"
#include "capture_data.h"
#include "Scanner.h"
ThreadsafeQueue<int> g_queue_1;
SCANNER_API ThreadsafeQueue<int> g_queue_2;
CaptureData::CaptureData(double test)
: m_test(test) {}
void CaptureData::get_data()
{
cout << "1: " << m_test << std::endl;
Sleep(5000);
cout << "2: " << m_test << std::endl;
g_queue_2.push(3);
cout << "Capture has now pushed data" << std::endl;
}
And finally the TestApp.cpp:
#include "stdafx.h"
#include "tchar.h"
#include <stdint.h>
#include <string>
#include "Scanner.h"
SCANNER_API extern ThreadsafeQueue<int> g_queue_2;
int _tmain(int argc, _TCHAR* argv[])
{
Scanner scanner;
scanner.run();
cout << "TestApp waiting for data..." << std::endl;
int data;
g_queue_2.wait_and_pop(data);
cout << "TestApp got data: " << data << std::endl;
scanner.stop();
return 0;
}
In Scanner.cpp I have tried to launch the thread in two different ways, the first way:
auto t = std::async(std::launch::async, &CaptureData::get_data, capture_data);
Second way is with a reference to the object "capture_data":
auto t = std::async(std::launch::async, &CaptureData::get_data, &capture_data);
The first way seems to work as I intended the application to work and I get the following printouts in my terminal:
TestApp waiting for data...
1: 1234
2: 1234
Capture has now pushed data
TestApp got data: 3
Press any key to continue...
If I use the second way I get:
TestApp waiting for data...
1: 6.95166e-310
2: 6.95166e-310
Capture has now pushed data
TestApp got data: 3
Press any key to continue...
So, what I do not understand is why the variable "m_test" get messed up in the second case.
I would very much appreciate if anyone could shed a light on this.
/M
In the following code:
void Scanner::run()
{
CaptureData capture_data(1234);
auto t = std::async(std::launch::async, &CaptureData::get_data, capture_data);
my_futures.push_back(std::move(t));
}
capture_data is a local variable that goes out of scope and gets destroyed when the function returns. If you pass a pointer to that variable into async that pointer becomes a dangling pointer causing undefined behaviour. That does not happen if you pass it by value, as you do in the above snippet.
You are trying to pass a pointer to a stack allocated object. This object is destructed at the end of the Scanner::run() method. Thus, the pointer is now pointing to invalid memory when the async function runs.
The first method works, because the capture_data variable is move constructed when it is passed to the function, therefore it still retains it's structure.
I recommend using lambda functions than passing the raw member function:
void Scanner::run()
{
CaptureData capture_data(1234);
auto t = std::async(std::launch::async, [capture=std::move(capture_data)]() { capture.get_data(); });
my_futures.emplace_back(t);
}
Even better is to construct the object inside the lambda function:
void Scanner::run()
{
auto t = std::async(std::launch::async, []() {
CaptureData capture_data(1234);
capture_data.get_data();
});
my_futures.emplace_back(t);
}

Boost ASIO socket io_service.run blocking

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?

How lock_guard<mutex> constructor can be compiled fine without mutex instance?

I am studying about threads in C++11 now, and I met the following line of code:
lock_guard<mutex> lg(mutex);
There is no variable mutex. mutex is only name of type.
Can anyone explain me how above line of code works?
Why compiler(GCC) doesn't print any error?
Complete code:
#include <iostream>
#include <thread>
#include <mutex>
#include <chrono>
using namespace std;
void do_something()
{
lock_guard<mutex> lg(mutex);
cout << "Working..." << endl;
this_thread::sleep_for(chrono::milliseconds(3000));
}
int main()
{
thread thd(do_something);
thd.join();
}
The compiler thinks this is a prototype function declaration:
lock_guard<mutex> lg(mutex);
To be clear, the compiler parses this as the declaration of a function named 'lg' which takes a mutex as a parameter and returns a lock_guard instance.
#include <mutex>
int main()
{
using namespace std;
lock_guard<mutex> lg(mutex);
return 0;
}
vc12 output : warning C4930 : 'std::lock_guard<std::mutex> lg(std::mutex)' : prototyped function not called(was a variable definition intended ? )
In C++ structure, class, enumeration and union names are in their own namespace (not a C++ namespace), which allows you to have variables with the same name as a structure.
For example:
struct SomeStruct
{
// Member...
};
SomeStruct SomeStruct; // Valid declaration
As for you not getting an error, if the function you use the shown it in a member function, then it could be that the class has a member variable with the name mutex.

Emit safely a signal from a thread and connect it to a widget

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.