Job queue

If you have a cool piece of software to share, but you are not hosting it officially yet, please dump it in here. If you have code snippets that are useful, please donate!
Post Reply
eranif
Moderator
Moderator
Posts: 610
Joined: Tue Nov 29, 2005 7:10 pm
Location: Israel

Job queue

Post by eranif »

Hi,

When working with threads, you often find yourself coding the same code again and again (derive from wxThread, implement Entry() bla bla bla)

attached you can find my implementation of JobQueue - a classes which manages pool of threads that allows applications to perform background tasks easily with minimum code

sample.cpp which shows how to use JobQueue

Code: Select all


class MyJob : public Job {
public:	
	MyJob(){}
	~MyJob(){}
	
	// Implement your processing code here
	void Process() {
		wxPrintf(wxT("Just doing my work...\n"));
	};
};

// define some custom job with progress report
class MyJobWithProgress : public Job {
public:	
	MyJobWithProgress(wxEvtHandler *parent) : Job(parent){}
	~MyJobWithProgress(){}
	
	// Implement your processing code here
	void Process() {
		// report to parent that we are at stage 0
		Post(0, wxT("Stage Zero"));
		// do the work
		wxPrintf(wxT("Just doing my work...\n"));
		// report to parent that we are at stage 1
		Post(1, wxT("Stage Zero Completed!"));
	};
};

// somewhere in your code, start the JobQueue
// for the demo we use pool of size 5
JobQueueSingleton::Instance()->Start(5);

// whenever you want to process MyJob(), just create new instance of MyJob() and add it to the JobQueue
JobQueueSingleton::Instance()->AddJob( new MyJob() );

// at shutdown stop the job queue and release all its resources
JobQueueSingleton::Instance()->Stop();
JobQueueSingleton::Release();

// OR, you can use JobQueue directly without the JobQueueSingleton wrapper class
// so you could have multiple instances of JobQueue
And the parent handles the status reports like this:

Code: Select all

// in the event table
EVT_COMMAND(wxID_ANY, wxEVT_CMD_JOB_STATUS, MyFrame::OnJobStatus)

void MyFrame::OnJobStatus(wxCommandEvent &e)
{
    wxString msg;
    msg << wxT("Job progress: Stage: ") << e.GetInt() << wxT(" Message: ") << e.GetString();
    wxLogMessage(msg)
}

Eran
Attachments
JobQueue.zip
(3.47 KiB) Downloaded 1985 times
Last edited by eranif on Fri May 09, 2008 2:33 pm, edited 2 times in total.
IDE: CodeLite + wxCrafter
OS: All
https://wxcrafter.codelite.org
https://codelite.org
phlox81
wxWorld Domination!
wxWorld Domination!
Posts: 1387
Joined: Thu Aug 18, 2005 7:49 pm
Location: Germany
Contact:

Post by phlox81 »

Nice. But I think you should think some more about the implementation Details. (Use of delete, JobQueue beeing a singleton, and beeing copyable f.e.)
QT has a nice ThreadPool implementation, so adding a Map Reduce Algorithm could also be nice.

phlox
eranif
Moderator
Moderator
Posts: 610
Joined: Tue Nov 29, 2005 7:10 pm
Location: Israel

Post by eranif »

Use of delete, JobQueue beeing a singleton, and beeing copyable f.e
Are you suggesting to make JobQueue as non-singleton object?

Also before making JobQueue copyable, you need to define what 'copyable' of thread is - Will the queue of jobs will also be copied? or just copy the pool size?
QT has a nice ThreadPool implementation, so adding a Map Reduce Algorithm could also be nice.
Wasn't this implemented in the recent version 4.4? (I have not got the time to look at QConcurrent yet)

Eran
IDE: CodeLite + wxCrafter
OS: All
https://wxcrafter.codelite.org
https://codelite.org
Jorg
Moderator
Moderator
Posts: 3971
Joined: Fri Aug 27, 2004 9:38 pm
Location: Delft, Netherlands
Contact:

Post by Jorg »

Very nice. Maybe donate it to the wxWidgets community also? It looks small and abstract enough to be useful in a lot of areas. What however misses here (I haven't looked into your code, I only assume) are syncrhonous message channels, or mailboxes. For example when the job needs input from other threads or the main thread or wishes to input status info, I would like to see a synchronous way of reporting back. Something like;

JobQueue -> Msg Poll Thread -> ::wxPostevent with custom event

The msg poll thread is one thread of JobQueue dedicated to polling for statuses to be returned to the main thread. Once there is something to report back, a custom message is sent back to the main GUI as a simple event in which the user can update whatever needs to be updated.

Other mechanisms to communicate between job threads and the main thread (or other threads if needed) could be a mailbox mechanism in which you can post a message, and the main GUI can check if there are messages to process (by use of the event mechanism described above) or even post messages to a specific job, totally thread safe.

I have seen and answered so many questions about race condions and using GUI stuff inside a thread that there must be a strong need for a simple but powerful solution that can couple a thread to the GUI. And your JobQueue mechanism seems to be straight forward but abstracted enough from thread(s) that it can be very helpful!

- Jorgen
Forensic Software Engineer
Netherlands Forensic Insitute
http://english.forensischinstituut.nl/
-------------------------------------
Jorg's WasteBucket
http://www.xs4all.nl/~jorgb/wb
phlox81
wxWorld Domination!
wxWorld Domination!
Posts: 1387
Joined: Thu Aug 18, 2005 7:49 pm
Location: Germany
Contact:

Post by phlox81 »

eranif wrote:
Use of delete, JobQueue beeing a singleton, and beeing copyable f.e
Are you suggesting to make JobQueue as non-singleton object?
Well, you could leave that to the user, of supply a SingletonJobQueue.
But also your implementation now has some lacks:
Instance() could return a reference, otherwise you could easily do a delete Instance(); (usersfault, I know).
Also, havin a Singleton with a release Method, is not really the thought of singleton.
Also note, that there is actually no thread safe singleton.

Also, you might give the user the ability to decide, wether a job should get deleted after its done, or not.
Also before making JobQueue copyable, you need to define what 'copyable' of thread is - Will the queue of jobs will also be copied? or just copy the pool size?
QT has a nice ThreadPool implementation, so adding a Map Reduce Algorithm could also be nice.
Wasn't this implemented in the recent version 4.4? (I have not got the time to look at QConcurrent yet)
Yes I think so, I have read about it a few month ago.

phlox
eranif
Moderator
Moderator
Posts: 610
Joined: Tue Nov 29, 2005 7:10 pm
Location: Israel

Post by eranif »

Instance() could return a reference, otherwise you could easily do a delete Instance(); (usersfault, I know).
Not really..
If u will have a closer look at the code, you will notice that the destructor is private which prevents the user from calling

Code: Select all

delete JobQueue::Instance();
lso, havin a Singleton with a release Method, is not really the thought of singleton.
Ofc it does, how else would you expect user releasing the singleton?
Also note, that there is actually no thread safe singleton.
We could achieve this by using the compiler global/static initialization method, for example:

Code: Select all

JobQueue* JobQueue::ms_instance = new JobQueue();
and changing the Instance() method to just return the inner member:

Code: Select all

JobQueue* JobQueue::Instance()
{
	return ms_instance;
}
the above code makes sure that the singleton is constructed before any of the threads will access it.

Eran
IDE: CodeLite + wxCrafter
OS: All
https://wxcrafter.codelite.org
https://codelite.org
phlox81
wxWorld Domination!
wxWorld Domination!
Posts: 1387
Joined: Thu Aug 18, 2005 7:49 pm
Location: Germany
Contact:

Post by phlox81 »

eranif wrote:
lso, havin a Singleton with a release Method, is not really the thought of singleton.
Ofc it does, how else would you expect user releasing the singleton?
So far I have never released a singleton in my life.
Maybe there is a usecase for it, if you want to restart the queue or so. So providing an Interface makes sense.

But still, what if the user wants to have several Instances?

phlox
eranif
Moderator
Moderator
Posts: 610
Joined: Tue Nov 29, 2005 7:10 pm
Location: Israel

Post by eranif »

But still, what if the user wants to have several Instances?
Ok, I modified the source files (first post) so JobQueue is no longer a singleton. If you want a singleton functionality, use the wrapper class JobQueueSingleton (as you advised)
Jorg wrote:Other mechanisms to communicate between job threads and the main thread (or other threads if needed) could be a mailbox mechanism in which you can post a message, and the main GUI can check if there are messages to process (by use of the event mechanism described above) or even post messages to a specific job, totally thread safe.
I added to Job class the following methods:

Code: Select all

Job::Post(int, wxString);
Job::Post(void *ptr);
these methods allows user to post int && string or a user defined class (by using the second method) to the parent (of type wxEvtHandler).

The parent is passed to the Job in the constructor.

The events are simple wxCommandEvent with defined type:

Code: Select all

wxEventType wxEVT_CMD_JOB_STATUS;
wxEventType wxEVT_CMD_JOB_STATUS_VOID_PTR;
Eran
IDE: CodeLite + wxCrafter
OS: All
https://wxcrafter.codelite.org
https://codelite.org
Jorg
Moderator
Moderator
Posts: 3971
Joined: Fri Aug 27, 2004 9:38 pm
Location: Delft, Netherlands
Contact:

Post by Jorg »

Cool sounds good. The reason I suggested a single thread extra for JobQueue is that if thead fire up a lot of messages to be processed by the GUI thread you don't want them to be too densely packed or the gui gets laggy. So if the seperate thread handles the communication on a +/- 100ms interval, or intelligent like sleeping more when nothing happened in a longer time, it would relieve the GUI.

But, good job I will check it out soon!

- Jorgen
Forensic Software Engineer
Netherlands Forensic Insitute
http://english.forensischinstituut.nl/
-------------------------------------
Jorg's WasteBucket
http://www.xs4all.nl/~jorgb/wb
Post Reply