Re: Multithreading application



On 16/03/2007 07:43, Govinda Parida wrote:
> Hi Niko Demmel
>  
> What you have replied me is correct. That is what i need to do.
>
> On 3/16/07, *Niko Demmel* <niko demmel gmx de
> <mailto:niko demmel gmx de>> wrote:
>
>
>     I havent looked at your serial code, but the question is how to
>     the two
>     windows and the serial port class has to interact with the two
>     windows.
>     Is all you need for window 1 to start the thread reading from the
>     serial
>     port and close when good data arrived and for window 2 to just get
>     displayed after 1 closes? Surely not?
>

Look at the example attached.

Just add the code for your terminal in the thread function and provide
your own window2. That should do it.

Watch out for this: I had a very brief look at the terminal code. You
might need to register any IO handlers in the main thread in your
MyWindow1 class. Those handlers could then forward the message to the
new thread (Use mutex if neccessary). Look at the gtkmm docs for this
(e.g. the tutorial @
http://www.gtkmm.org/docs/gtkmm-2.4/docs/tutorial/html/ch21s02.html).
I'm not sure what happens if you register a IO handler in the other
thread (might work aswell).
#include <iostream>
#include <glibmm/thread.h>
#include "gtkmm.h"

class ThreadProgress : public sigc::trackable
{
public:
  explicit ThreadProgress();
  virtual ~ThreadProgress();

  void launch();
  void join();
  
  // use this to stop thread prematurely
  void stop();

  sigc::signal<void>& signal_finished_success();

  virtual void reference() const { ++ref_count_; }
  virtual void unreference() const { if (!(--ref_count_)) delete this; }

private:
  bool stop_flag_;
  Glib::Thread*       thread_;
  unsigned int        progress_;
  sigc::signal<void>  signal_finished_success_;

  void thread_function();  

  mutable int ref_count_;
 
};

class MyWindow1: public Gtk::Window
{
public:
	MyWindow1(bool& success);
	virtual ~MyWindow1();
    
protected:
    Gtk::VBox vbox;
    Gtk::Label label;
    Gtk::Button button;
    
    Glib::RefPtr<ThreadProgress> progress_;
    Glib::Dispatcher  dispatcher_finished_success_;
	
	void launch_threads();
    void signal_finished_success_handler();   
	
	bool& success_;
    
};

class MyApplication
{
public:
	void run();
	
private:
	bool run_window2;
	// data
};

void MyApplication::run()
{	
	run_window2 = false;
	
	// let win1 be deleted before win2 starts. not neccesary but (memory-) efficient
	{
		MyWindow1 win1(run_window2);
		Gtk::Main::run(win1);
	}
	
	// only start window 2 if window one did set run_window2 to true
	if(run_window2)
	{
		Gtk::Window win2;
		Gtk::Main::run(win2);
	}
}

ThreadProgress::ThreadProgress()
:
  thread_   (0),
  progress_ (0),
  ref_count_(0),
  stop_flag_(false)
{
  // Increment the reference count
  reference();
}

ThreadProgress::~ThreadProgress()
{}

void ThreadProgress::launch()
{
  // Create a joinable thread.
  stop_flag_ = false;
  thread_ = Glib::Thread::create(sigc::mem_fun(*this, &ThreadProgress::thread_function), true);
}

void ThreadProgress::join()
{
  thread_->join();
  thread_ = NULL;
}

void ThreadProgress::stop()
{
	stop_flag_ = true;
}

sigc::signal<void>& ThreadProgress::signal_finished_success()
{
  return signal_finished_success_;
}

void ThreadProgress::thread_function()
{
	// set this true when data are good
	bool successful = false;
	
	// start your terminal here... dont just sleep 3 ses
	int i = 0;
	while(!stop_flag_)
	{
		++i;
		Glib::usleep(30000); // Microseconds
		if(i >= 100)
			break;
	}
	// for this example we consider success when we havent been forced to stop
	if(!stop_flag_)
		successful = true;
	
	// if data are good, send finish signal
	if(successful)
		signal_finished_success_();
	// if not, send other signal if you want to
//	else
//		signal_bad_data_();
}

MyWindow1::MyWindow1(bool& success):
	label("ready to go"),
	progress_(new ThreadProgress),
	button("start terminal thread"),
	success_(success)
{
	// signals from the thread
	progress_->signal_finished_success().connect(
        sigc::mem_fun(dispatcher_finished_success_, &Glib::Dispatcher::emit));
	dispatcher_finished_success_.connect(
        sigc::mem_fun(*this, &MyWindow1::signal_finished_success_handler));
			
	button.signal_clicked().connect( 
		sigc::mem_fun(*this, &MyWindow1::launch_threads) );
	
    //maximize();
    //set_default_size(400, 370);
    add(vbox);
    vbox.pack_start(label, Gtk::PACK_SHRINK);
	vbox.pack_start(button);
    show_all_children();
}   
    
MyWindow1::~MyWindow1()
{
	// wait for the thread if not finished... 
	// ideally we want to make the thread abort prematurely
	// here we just wait
	if(progress_)	
	{
		// set stop flag, then join
		progress_->stop();
   		progress_->join();
   		progress_.clear();
	}
}

void MyWindow1::launch_threads()
{
    label.set_label("launching terminal thread - wait until it finishes (3 secs) or abort by closing the window");
	progress_->launch();
}

void MyWindow1::signal_finished_success_handler()
{
    progress_->join();
    progress_.clear();
    label.set_label("finished successfully - closing window 1 in 3 seconds");
    // consider this success
    success_ = true;
    Glib::signal_timeout().connect(
      	sigc::bind_return(sigc::mem_fun(*this, &MyWindow1::hide), false), 3000);
}

int main(int argc, char** argv)
{  
	Gtk::Main main(argc, argv);
	Glib::thread_init();
 
	MyApplication app;
	app.run();	
  
	return 0;
}


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]