// JP opened flex table

Click to See Complete Forum and Search --> : Thread in c++


MFCQuery
October 11th, 2007, 04:33 AM
Hi,

Please give a sample to use thread in c++. Without thread main application dont response to user. It looks like program is hang. If i use a thread then main application will responce.

Zaccheus
October 11th, 2007, 10:31 AM
Which OS ?

Marc G
October 11th, 2007, 11:58 AM
[ moved thread ]

JVene
October 11th, 2007, 04:56 PM
With objects that represent threads (and related metaphors), it's fairly simple:

...this is pseudo code, not checked or meant to compile....

Also, this assumes a wxWidgets framework base, and is therefore cross platform.



void CustomPanel::OnMouseLUp( wxMouseEvent & e)
{
if ( ....some test that a long running function should be called ... )
{
PanelQue.Call( this, &CustomPanel::SomeFunc );
}
}


void CustomPanel::SomeFunc()
{
... this function now runs in a thread
}





Here's what this implies....

CustomPanel represents some window, and a message has been received which indicates some function should be called that might take more time than UI should allow, so it should be threaded.

A member of CustomPanel is declared thus:

QueProcessor PanelQue;


PanelQue is a QueProcessor object, which presents a thread and a queue of 'pointers to member functions'. It's an object from my own library which I've developed for myself over the years (the original version was written for OS/2 when 'threading' was new).

When a CustomPanel is created, the construction of the members of the CustomPanel object include the PanelQue, which, as the result of ITS default constructor, launches a thread and holds in waiting on an event (or condition for Linux).

Then, at any time, when the 'Call' function of the PanelQue is called, it accepts a pointer to the member function of CustomPanel that should be run on the PanelQue's thread. The main thread returns to the OS, ready to continue pumping messages.

The condition or event is signaled by the 'Call' function, to indicate that the PanelQue thread, which was waiting and thus suspended, should 'wake up' and service any pending entries in it's internal queue container. PanelQue can, in theory, call any member function of any object, as long as it's guaranteed to remain in scope as along as PanelQue is, and there are overrides of 'Call' which accept a few parameters. The Call function in PanelQue are template functions, so they can 'mutate' to any object and parameter type.

Call creates a template object (I call it a Proc<T>), which represents a pointer to the member function. It takes a pointer to the object upon which the call is to be made, a pointer to the function, references to any parameters (if they're supplied), and appends this Proc<T> object to the queue container owned by PanelQue. The event (or condition) is signaled so that PanelQue's own thread will service the queue.

Now, there's some work involved in launching a thread, which I've trivialized into the creation of a QueProcessor object, and I suggest you consider something similar. As you can see, it greatly simplifies what you must think about when implementing a thread for the purpose of freeing up UI.

The main 'Process' of the thread which QueProcessor runs is simply a loop that waits on an event, and at each cycle of that loop checks to see if the destructor has been called, so as to indicate a shutdown of the QueProcessor, or if there are any pending entries in the queue container that represent processes to be run as jobs. The queue container accepts, in my case, an unlimited number of jobs, but you can establish practical thresholds if you like. You can stuff new jobs into the queue while it's busy serving existing tasks, and it will call the entries in the queue, one at a time, in order, until the queue is exhausted.

This has two main benefits. First, you can respond to a UI request (like a button or comman) without having the burden of launching a thread in order to perform the response. A thread is waiting (and is quite 'light' duty for the OS).

Second, you're no longer thinking in terms of 'threads' for each response process. You're not building an object for each threaded objective. You can simply decide at some point you want a thread to do the job, add a QueProcessor member, call the function to be threaded and move on.

If you take the time to build a few objects for your threading, you'll find yourself reaching for threaded solutions as if they were trivial function calls. You'll still need to 'think' about the objective, there is no magic - it's just that there's hardly any real effort associated with implementing threads any more. In my own case, the solution is portable, so one body of application code (generally) works for Linux, Windows and Mac.

You still need synchronization objects to consider. You'll want an 'event' object. For my own work, I have a Windows version and a Linux version of the event (an AutoResetEvent and I have occasional use for the ManualResetEvent). This object is implemented differently on Linux than on Windows, but since the interface is identical, the application code has no 'recognition' of that fact, so one body of application code ports over the platforms without effort (or defines, etc.). Simple member functions for signaling and waiting complete the object.

You'll serve yourself well by creating a Sync and a Lock object of some kind. Windows has the 'critical section' whereas Linux relies on Mutexes, but conceptually they are identical notions. As such, the Sync represents the critical section or mutex (for the corresponding OS). It's job is simply to initialize and shutdown the mutex.

Now, most frameworks have a mutex object of some kind. They offer the 'lock' and 'unlock' functions, but that's a bad design. You can lock a mutex and forget to unlock it, or by way of an exception fail to unlock it, creating a deadlock.

So, create an all inline object representing a lock. It's sole purpose is to lock against the sync on it's creation, and unlock on it's exit. Every time, without fail, even under exceptions.

Now, in Linux, the notion of the mutex isn't re-entrant. That is, you can't lock a mutex upon which that thread already has a lock. Windows, on the other hand, especially when using the critical section, has no problem with this. That is, a lock on a critical section for which that thread already has a lock is allowed, as long as the corresponding unlocks are performed 'on the way out' of whatever process does this. It's not that common, but in my Linux versions of 'lock' - I emulate this feature so my application code doesn't have any reason to differentiate between the two.

After those few objects, there are a host of other notions that can be helped with objects, but I'll leave that for you're own research. Simple hint - Windows doesn't have a pthread_join, unless you employ a third party POSIX thread solution (maybe it's by MS, I don't know, but it's not the default). I prefer object solutions that aid portability, so I have an object that represents the notion of joinable threads (the notion that some 'main' thread calls upon a few threads to perform some work, and must wait for all of them to finish before proceeding).

MFCQuery
October 11th, 2007, 08:27 PM
OS-windows xp

please give any sample

Arjay
October 12th, 2007, 01:54 AM
Check out the Simple Thread: Part II article in my subject line.

It's a small example that uses a string shared between two threads and illustrates setting the string in an unsafe manner as well as setting the string using a critical section.

This article is very basic is intended to show the problems associated with sharing data between threads when synchronization isn't used.

For a better thread safe technique using RAII, check out the Win32 thread synchronization articles listed.

//JP added flex table