0

I'm trying to get my hands on multi threading and it's not working so far. I'm creating a program which allows serial communication with a device and it's working quite well without multi threading. Now I want to introduce threads, one thread to continuously send packets, one thread to receive and process packets and another thread for a GUI.

The first two threads need access to four classes in total, but using pthread_create() I can only pass one argument. I then stumled upon a post here on stack overflow (pthread function from a class) where Jeremy Friesner presents a very elegant way. I then figured that it's easiest to create a Core class which contains all the objects my threads need access to as well as all functions for the threads.So here's a sample from my class Core:

/** CORE.CPP **/

#include "SerialConnection.h"   // Clas for creating a serial connection using termios
#include "PacketGenerator.h"    // Allows to create packets to be transfered 
#include <pthread.h>

#define NUM_THREADS 4

class Core{
private:
  SerialConnection serial;    // One of the objects my threads need access to
  pthread_t threads[NUM_THREADS];
  pthread_t = _thread;

public:
  Core();
  ~Core();
  void launch_threads();    // Supposed to launch all threads
  static void *thread_send(void *arg);    // See the linked post above 
  void thread_send_function();    // See the linked post above
};

Core::Core(){
  // Open serial connection
  serial.open_connection();
}

Core::~Core(){
  // Close serial connection
  serial.close_connection();
}

void Core::launch_threads(){
  pthread_create(&threads[0], NULL, thread_send, this);

  cout << "CORE: Killing threads" << endl;
  pthread_exit(NULL);
}

void *Core::thread_send(void *arg){
  cout << "THREAD_SEND launched" << endl;
  ((Core *)arg)->thread_send_function(); 
  return NULL;
}

void Core::thread_send_function(){
  generator.create_hello_packet();
  generator.send_packet(serial);
  pthread_exit(NULL);
}   

Problem is now that my serial object crashes with segmentation fault (that pointer stuff going on in Core::thread_send(void *arg) makes me suspicious. Even when it does not crash, no data is transmitted over the serial connection even though the program executed without any errors. Execution form main:

/** MAIN.CPP (extract) VARIANT 1 **/
int main(){
  Core core;
  core.launch_threads();    // No data is transferred
}

However, if I call the thread_send_function directly (the one the thread is supposed to execute), the data is transmitted over the serial connection flawlessly:

/** MAIN.CPP (extract) VARIANT 1 **/
int main(){
  Core core;
  core.thread_send_function();    // Data transfer works
}

Now I'm wondering what the proper way of dealing with this situation is. Instead of that trickery in Core.cpp, should I just create a struct holding pointers to the different classes I need and then pass that struct to the pthread_create() function? What is the best solution for this problem in general?

Community
  • 1
  • 1
Potaito
  • 1,181
  • 2
  • 10
  • 32

1 Answers1

3

The problem you have is that your main thread exits the moment it created the other thread, at which point the Core object is destroyed and the program then exits completely. This happens while your newly created thread tries to use the Core object and send data; you either see absolutely nothing happening (if the program exits before the thread ever gets to do anything) or a crash (if Core is destroyed while the thread tries to use it). In theory you could also see it working correctly, but because the thread probably takes a bit to create the packet and send it, that's unlikely.

You need to use pthread_join to block the main thread just before quitting, until the thread is done and has exited.

And anyway, you should be using C++11's thread support or at least Boost's. That would let you get rid of the low-level mess you have with the pointers.

Sebastian Redl
  • 69,373
  • 8
  • 123
  • 157
  • Thanks a lot, very good answer. I thought the problem lies much deeper, but your explanation makes perfect sense. Tomorrow I'll definitely try std:thread or Boost! – Potaito Sep 19 '13 at 16:08