multithreaded apps and thread communication
| Thu, 2007-11-29 20:07 | |
|
Hi all, I have an application that uses threads. Threads by default do not have an ActiveScheduler installed and therefore I cannot use CActive-stuff from threads that were started by me. So, I creat a new active scheduler and set it for every new thread, but the problem is that threads that I create run some long function (like a loop with waits) and then exits, and therefore active objects never fire in my threads. The thing is that once some condition happens in any of that created threads I need to create CActive derived objects and add it to the scheduler... so I need them somehow to add to the main scheduler in the main thread so that the active object could be processed correctly. Did I describe clearly what kind of problem I have? I have two symbian books and none of them can help me with that problem, so I decided to ask it here. Thanks |
|






Forum posts: 1246
The active scheduler exists and works entirely within the execution flow of ONE thread.
It is not possible to share them between threads, because of how they work internally.
And contrary to the operating system thread scheduler, the active scheduler is NOT pre-emptive, as you have noticed.
The principle of the active scheduler is actually quite simple, it is an infinite loop, that waits on the thread request semaphore.
semaphores work such that the thread waiting on it will sleep and do nothing until the semaphore signaled.
When a signal arrives, scheduler will run again and will look through its list of active objects for the first one, with highest priority, marked as completed, and call RunL for it.
And when RunL returns, it will again wait on the semaphore.
Naturally, no other active objects can thus be handled until the RunL has returned...
This also means that AS applications (like normal UI apps), will ALWAYS execute within one of its RunLs in the code you write, even though you might not always see the RunL, because its hidden by the framework.
So... what to do?
Im assuming you can't divide the work the threads do into parts, to work well with the AS/AO framework... (If you could, using threads is often not needed in the first place (but can still be sometimes))
What you need then, is some way for the long running task to signal the main thread to add an active object to its AS.
One way to do this could be to use P&S.
You can define a number of P&S values, that you set from the long running thread, and listen for changes on from the main thread.
one of the threads to RProperty::Define, and then the long running one use RProperty::Set.
The main thread needs an AO that uses RProperty::Subscribe() to listen for changes, and performs whatever function is requested throuhg the P&S value
One drawback: if you need to send a lot of messages very quickly, you might have problems with missed messages useing this method... If so, you could use an RMessageQueue to never lose any commands.
But if it is just once now and then (not much more then a few times a second), the P&S way should work.
Forum posts: 116
Hi,
If I well understood your problem, your problem is about sending some events from the child thread to the main thread and handling/processing those events in the main thread.
First of all, concerning activescheduler and active objects there are lots of tutorials and posts in the forum that discuss the issue.
Concerning sending event from child thread to main thread, you can use publish/subscribe or message queues.
If you wish to handle the events in the respective thread you can do so by adding the active objects to the respective scheduler and starting the scheduler loop.
So your thread function looks
Chao,
Raghav
Forum posts: 32
alh & raghav_an, thanks both your answers helped, that's what I needed - to know how to send event from one thread to another. I understand one part of how active scheduler works, that it has infinite loop and it dispatches events to handlers, whatever, but other part is mysterious to me, that part related to thread semaphore, how it waits for that semaphore, where this semaphore comes from, is it always one such semaphore in a thread. Can another thread modify main thread's iStatus in any of active objects and then signal semaphore so that main thread runs RunL on respective iStatus?
It's all so bad that symbian is c++ and it hides that implementation without providing enough documentation. I actually got two books and none of them discuss that part of threading and active objects. And yes, for sure I want to remove threads, that's on TODO list, but for now I need to make it work as is.
thanks
Forum posts: 1246
"dispatch of message" is just a simple function call of the RunL function.
The "thread request semaphore" is part of the OS IPC framework, and every thread has one, the OS makes sure it does.
Semaphores in themselfs are a basic thread control mechanism, it doesn't matter exactly how they are implemented as long as they fulfill the specification on how semaphores should work.
This is basicly: "Put any thread to sleep that calls Wait(), until any (other) thread has called Signal()"
It also has a counter, so you can call "Signal()" for example 3 times, and then "Wait()" will immediatly return and not sleep the next 3 times it is called.
This is how the framework handles more then one request incomeing at the same time.
And the loop works something like this:
FOREVER { //wile (1) // Wait on semaphore // Look through list of added and activated AOs in priority order // Call the RunL of the first one that has value "ERequestComplete" // If noone is found raise panic "Stray Signal" (E32User-CBase 46) }No more...
Request are completed with the help of the kernel, since the kernel can write in any process memory space.
So when thread 1 want to complete a message request that thread 2 has send, it simply instructs the kernel to set the TRequestStatus to ERequestComplete and call "Signal()" on the semaphore of thread 2
And thats basicly it...
Forum posts: 110
Yes that's the whole point (and it's also the reason why the designers made iStatus a public member of CActive. Normally you'd expect data members of CBase derived classes to be private)
That's because it's difficult. You can do thread communication using active objects but it can be fiddly and error prone (although if you can make it work it is also the most efficient method). For threads that just want to "talk to each other" you might be better off with RMsgQueues or some other form of communication. It just depends on what you want to do.
Forum posts: 1246
In EKA1 it is possible to access memory of another process, in EKA2 it is not.
Therefore, in EKA2 you need to use kernel functions like RThread::Complete() to modify the value of iStatus and increase the thread semaphore.
And if we are going technical, the variable being public has nothing to do with this part, the C++ data hiding is just hiding, it does not affect process memory isolation, you can still modify private variables as long as you can map the process memory space.
Though, it has to be public to make it possible to (easily) write C++ code that modify or inspect it from another class, which is useful both for the active scheduler implementation and implementation of in-process asyncronous services...
Forum posts: 32
So... as I understood memory of one thread is not accessible from another thread in EKA2, is that correct? (More specifically I care about UIQ3, is it EKA2?)
public vs private is only used for convinience and has nothing to do with data access. Sometimes I need to write some quick code where I need to modify some private/protected members and for that i simply used #define private public instead of modifying classes themselves
Forum posts: 32
I just looked at RProperty docs and it's a nightmare, I have no idea how to use it to notify a thread about some event!!
First of all, RPoperty::Define has so many arguments and each of them doesn't really mean anything to me, documentation is useless. There's no examples that use RProperty also. It seems to be to complicated to get that simple task done.
Similar task could be done with events in windows: CreateEvent, waitForMultipleObjects, SetEvent. However windows docs are very clear and have many examples, symbian docs are written only for those who wrote symbian, so that they use it as a quick reference.
Is there any place I could see how to use RProperty? I saw a couple of places where it's used and everywhere it's something related to Bluetooth.
static IMPORT_C TInt Define(TUid aCategory, TUint aKey, TInt aAttr, TInt aPreallocate=0);
there are three predefined categories, which one I need? What's that aKey and aAttr?!?!? What a messs.sssss..s.s.s.s
Can I simply get the main thread id or handler, then create some AO in the main thread and then from some other thread set iStatus of that object to active and signal the main thread so that it executes my AO??
thanks
Forum posts: 110
No threads in the same process share the same memory space. That's why it's perfectly possible to simply share data between threads and use AOs to signal each thread as and when needed (although you still potentially need locks if multiple threads want to write to the shared data).
If all you want to do is signal one thread that an event in another thread has completed then of course an AO is what you want. One common way of doing that is simply to make the child thread exit when it has completed its task. See RThread::Logon() for details of how to get notified when a thread terminates.
Forum posts: 683
mtlgui, there's a quite good article on Publish/Subscribe with RProperty on Symbian dev library.
Forum posts: 32
Yeah, I found that article by myself, and I posted a message about that and how to do that, but some how my msg is not on the board. Probably I clickd preview instead of post.
Ok... fig7, how do I notify a thread from another thread using AO?? I need to notify the main thread from another thread that doesn't have ActiveScheduler. My child thread off course terminates when it finishes it's task, but it's task is very long and it's of no use to me to know when it terminates, I don't need to know about that at all.
Forum posts: 110
Look at RThread::RequestComplete()