How to deal with shared data when throwing exceptions - c++

When having multiple threads using shared data, how does one correctly handle the destruction of that data when exceptions are thrown?
I'm working on an application where I want one process to be doing work while waiting for a result sent from another process over a network. I implemented a class that creates a thread to wait for the result, something like the following (actual code is too large to post here, so this is a small example):
class Notifier {
public:
Notifier(Client* _client) : value(-1), client(_client) {
listener = boost::thread(&Notifer::Listen, this);
}
void Listen() {
try {
int rec = client->Receive(); //blocking call to receive data over a socket
boost::scoped_lock sl(mutex);
value = rec;
} catch (...) {
cout << "Exception thrown in listener" << endl;
}
}
int Get() {
boost::mutex::scoped_lock sl(mutex);
return value;
}
private:
int value;
boost::mutex;
boost::thread listener;
Client* client;
}
int main() {
Client client; //initialize client, connect, etc.
Notifier n(client);
while(n.Get() < 0) {
// do work
cout << "Waiting for data" << endl;
sleep(1);
}
}
This works fine for me until I add exception handling:
int main() {
try {
Client client; //initialize client, connect, etc.
Notifier n(client);
while(n.Get() < 0) {
// do work
cout << "Waiting for data" << endl;
sleep(1);
throw exception();
}
} catch(...) {
cout << "Exception thrown in main" << endl;
}
return 0;
}
I get the error
"boost: mutex lock failed in pthread_mutex_lock: Invalid argument".
My guess is that, when the exception gets thrown, the stack for the main function gets unwound, destroying the mutex. Then the Receive() call in the Listen function returns and the scoped_lock constructor tries to lock the mutex, which doesn't exist, resulting in the error.
Can someone confirm that this is indeed what is happening? If so, is there a way to communicate to the thread that that the mutex no longer exists or that the thread should terminate? Or is there a more exception-safe way of doing what I'm trying to do?

You have to write a correct destructor for Notifier class, which would cancel all blocked calls (i.e. unblock client->Receive()) and then terminate listener thread. Also you need to modify Notifier::Listen() to periodically check for thread termination request... then everything will be Ok.

Related

Thread.joinable return true even thread hasn't finished executing

std::mutex MTX;
bool ExitThread = false;
//This function is running in a separate thread
//for constantly trying to connect to a server in a non blocking manner
void ClientConnectingLoop(sf::TcpSocket* client, std::string ipAddress,
unsigned short port)
{
std::cout << "Start" << std::endl;
MTX.lock();
std::cout << "Start2" << std::endl;
while(client->connect(ipAddress, port) != sf::Socket::Status::Done &&
!ExitThread)
{
}
std::cout << "Done" << std::endl;
MTX.unlock();
}
int main()
{
//Code for setting ipaddress and port is abstracted.
std::string ipAddress;
unsigned short port;
//Setup socket
sf::TcpSocket clientSocket;
clientSocket.setBlocking(false);
//Connect to server
std::thread ClientConnectThread(ClientConnectingLoop, &clientSocket, ipAddress, port);
std::cout << "Connecting to server......" << std::endl;
//Wait until it finishes executing, code inside this loop is abstracted
while(!ClientConnectThread.joinable())
{
}
//The thread is finished executing.
if(ClientConnectThread.joinable())
{
std::cout << "Joinable returned true" << std::endl;
ClientConnectThread.join();
}
//........
}
The problem comes to that the thread returns joinable (true) despite the loop in the thread is still running.
So that means the console outputs "Connecting to server......" => "Start" => "Start2" => "Joinable returned true" but "Done" should be printed after "Start2" unless I misunderstood joinable function
I am still fairly new to c++ and SFML, please be kind when pointing out any mistakes.
Quoting directly from cppreference.com
std::thread::joinable
Checks if the thread object identifies an active thread of execution. Specifically, returns true if get_id() != std::thread::id(). So a default constructed thread is not joinable.
A thread that has finished executing code, but has not yet been joined is still considered an active thread of execution and is therefore joinable.
Based on this, the idea of a joinable thread is different. A thread is always joinable except if has been default-constructed and has not been assigned to a function/method to run or if you have already called the thread.join() method on it.
An rather simple solution to the problem at hand would be to use some multithreading-aware locking construct such as std::atomic or void futures to communicate the result as suggested in the Effective Modern C++ book of Scott Meyers

Heavy CPU Usage on pthread

I have simple Application which receives messages through TCP Socket and process the same messages and Perform Some Actions.
I have used std::queue's to store the messages and process them on a thread.
Application is working fine with no crash. But, after few minutes the application consumes heavy cpu.
Here is my insert message and process message ( thread) code
My Simple Queue and thread veriables
std::queue<std::string> in_data_queue;
pthread_mutex_t in_data_queue_lock=PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t in_data_queue_condition=PTHREAD_COND_INITIALIZER;
Code For Processing Queue
void *processMessage(void *attr) {
while (true) {
try {
if (pthread_mutex_trylock(&in_data_queue_lock) == 0) {
if (!in_data_queue.empty()) {
std::string data = in_data_queue.front();
in_data_queue.pop();
pthread_cond_signal(&in_data_queue_condition);
pthread_mutex_unlock(&in_data_queue_lock);
// do some action ;
} else {
pthread_cond_wait(&in_data_queue_condition,
&in_data_queue_lock);
pthread_mutex_unlock(&in_data_queue_lock);
}
}
} catch (std::exception &e) {
cout << e.what() << endl;
}
cout << "processMessage" << endl;
}
pthread_exit(NULL);
}
Code For Insert the Message in Queue
void pushMessage(std::string rData) {
pthread_mutex_lock(&in_data_queue_lock);
in_data_queue.push(rData);
pthread_cond_signal(&in_data_queue_condition);
pthread_mutex_unlock(&in_data_queue_lock);
}
Any body help me what's the wrong with thread. Is that fine implementation or any issue on this thread. Please help me..

Catching exception from boost::asio::io_service::work running as a detached thread

I have my application main loop control where I do start a thread to handle asio work as follows:
void AsioThread::Run()
{
try
{
/*
* Start the working thread to io_service.run()
*/
boost::asio::io_service::work work(ioService);
boost::thread t(boost::bind(&boost::asio::io_service::run, &ioService));
t.detach();
while (true)
{
// Process stuff related to protocol, calling
// connect_async, send_async and receive_async
}
}
catch (std::runtime_error &ex)
{
std::cout << "ERROR IN FTP PROTOCOL: " << ex.what() << std::endl;
}
catch (...)
{
std::cout << "UNKNOWN EXCEPTION." << std::endl;
}
During the async operation, the handlers are called and sometimes I do throw exception on those handlers, like:
void AsioThread::ReceiveDataHandler(const boost::system::error_code& errorCode, std::size_t bytesTransferred)
{
std::cout << "Receive data handler called. " << bytesTransferred << " bytes received." << std::endl;
if (errorCode)
{
std::cout << "Error receiving data from server." << std::endl;
}
rxBufferSize = bytesTransferred;
/*
* Check for response
*/
std::string msg(rxBuffer);
if (msg.substr(0, 3) != "220")
throw std::runtime_error("Error connecting to FTP Server");
}
My problem is that the exception thrown inside the async handler (AsioThread::ReceiveDataHandler) is not catched by the main processing loop try...catch block in AsioThread::Run. Naturally this happens because the working thread t is on another thread, detached, and at runtime that leads to an execution error.
How can I receive exceptions from the detached boost::asio::io_service::work thread ? How can I structure my code to make this logic work ?
Thanks for helping.
You can catch exceptions in the worker thread, save them into a queue variable that is shared by the two threads, and check that queue periodically in the main thread.
To use a queue, you need to first convert your exceptions to a common type. You can use std::exception or string or whatever is the best for your situation. If you absolutely need to keep information of the original exception class, you can use boost::exception_ptr.
Variables you need (these could be members of AsioThread):
boost::mutex queueMutex;
std::queue<exceptionType> exceptionQueue;
Run this function in the worker thread:
void AsioThread::RunIoService(){
try{
ioService.run();
}
catch(const exceptionType& e){
boost::lock_guard<boost::mutex> queueMutex;
exceptionQueue.push(e);
}
catch(...){
boost::lock_guard<boost::mutex> queueMutex;
exceptionQueue.push(exceptionType("unknown exception"));
}
}
Launch the worker thread like this:
boost::thread t(boost::bind(&AsioThread::RunIoService, this));
t.detach();
In the main thread:
while(true){
// Do something
// Handle exceptions from the worker thread
bool hasException = false;
exceptionType newestException;
{
boost::lock_guard<boost::mutex> queueMutex;
if(!exceptionQueue.empty()){
hasException = true;
newestException = exceptionQueue.front();
exceptionQueue.pop();
}
}
if(hasException){
// Do something with the exception
}
}
This blog post implements a thread-safe queue, which you can use to simplify saving exceptions; in that case you would not need a separate mutex because that would be inside the queue class.

boost::asio signal_set handler only executes after first signal is caught and ignores consecutive signals of the same type

I have a program and would like to stop it by sending SIGINT for writing some data to a file instead of exiting immediately. However, if the user of the program sends SIGINT again, then the program should quit immediately and forget about writing data to a file.
For portability reason I would like to use boost::asio for this purpose.
My initial (simplified) approach (see below) did not work. Is this not possible or am I missing something?
The handler seems to be called only once (printing out the message) and the program always stops when the loop has reached the max iteration number.
void handler(
const boost::system::error_code& error,
int signal_number) {
if (!error) {
static bool first = true;
if(first) {
std::cout << " A signal(SIGINT) occurred." << std::endl;
// do something like writing data to a file
first = false;
}
else {
std::cout << " A signal(SIGINT) occurred, exiting...." << std::endl;
exit(0);
}
}
}
int main() {
// Construct a signal set registered for process termination.
boost::asio::io_service io;
boost::asio::signal_set signals(io, SIGINT);
// Start an asynchronous wait for one of the signals to occur.
signals.async_wait(handler);
io.run();
size_t i;
for(i=0;i<std::numeric_limits<size_t>::max();++i){
// time stepping loop, do some computations
}
std::cout << i << std::endl;
return 0;
}
When your first event is handled, you don't post any new work on the service object, so it exits.
This means that then (after the ioservice exited) the tight loop is started. This may not be what you expected.
If you want to listen for SIGINT again, you have to wait for the signal set again from the handler:
#include <boost/asio.hpp>
#include <boost/asio/signal_set.hpp>
#include <boost/bind.hpp>
#include <boost/atomic.hpp>
#include <iostream>
void handler(boost::asio::signal_set& this_, boost::system::error_code error, int signal_number) {
if (!error) {
static boost::atomic_bool first(true);
if(first) {
// do something like writing data to a file
std::cout << " A signal(SIGINT) occurred." << std::endl;
first = false;
this_.async_wait(boost::bind(handler, boost::ref(this_), _1, _2));
}
else {
std::cout << " A second signal(SIGINT) occurred, exiting...." << std::endl;
exit(1);
}
}
}
int main() {
// Construct a signal set registered for process termination.
boost::asio::io_service io;
boost::asio::signal_set signals(io, SIGINT);
// Start an asynchronous wait for one of the signals to occur.
signals.async_wait(boost::bind(handler, boost::ref(signals), _1, _2));
io.run();
return 2;
}
As you can see I bound the signal_set& reference to the handler in order to be able to async_wait on it after receiving the first signal. Also, as a matter of principle, I made first an atomic (although that's not necessary until you run the io_service on multiple threads).
Did you actually wish to run the io_service in the background? In that case, make it look like so:
signals.async_wait(boost::bind(handler, boost::ref(signals), _1, _2));
boost::thread(boost::bind(&boost::asio::io_service::run, boost::ref(io))).detach();
while (true)
{
std::cout << "Some work on the main thread...\n";
boost::this_thread::sleep_for(boost::chrono::seconds(1));
}
With typical output:
Some work on the main thread...
Some work on the main thread...
Some work on the main thread...
^CSome work on the main thread...
A signal(SIGINT) occurred.
Some work on the main thread...
Some work on the main thread...
^CSome work on the main thread...
A second signal(SIGINT) occurred, exiting....

Boost Thread - Create a Thread without join()

I have an application that creates a thread, and it will be listening for incoming connections. And the main thread will be doing other things.
boost::mutex mutex;
void
ThreadFunction(int port, int(*callbackFunc)(int, int))
{
mutex.lock();
std::cout << "Cannot get to this point" << std::endl;
mutex.unlock();
Application app;
app.run(port, callbackFunc);
}
void
Init(int port, int(*callbackFunc)(int, int))
{
std::cout << callbackFunc(1,1) << std::endl;
boost::thread t(boost::bind(&ThreadFunction, port, callbackFunc));
}
int
main(){
int port = 2340;
Init(port, *callbackfunction);
return 0;
}
The problem I am having is that it never access the std::cout << "Cannot get to this point" << std::endl; However, if I call join() after I create the thread, it works just fine but then it is blocking the application.
What do I need to do for the thread call the ThreadFunction?
Your application terminates (by leaving main()) before the thread gets a chance to do its work. Once you implement a wait-for-connections loop, the problem will be resolved. So, no need to do anything.