views:

174

answers:

6

Hi to all,

i'm developing a multi-threaded application and i'm here to ask for a little help :) As i don't have much experience in multi-threading, especially in win32 API and this is my very first experience with it, i just wanted to check if I'm on the right way with my abstract model. I have read a reasonable amount of literature before posting this question, such as almost entire Multi-Threading Applications in Win32 book and number of internet articles.

Let me explain thoroughly what this application is really about. Complete system is really consisted of two parts:

  • windows application that is needed to develop
  • external hardware that is measuring some data by using Silabs micro-controller

They communicate each other by USB protocol and drivers are not a problem as they're already delivered by Silabs. The one i am supposed to do is that application part.

So, my application should do the following tasks simultaneously:

  1. Show some images on a form (just like a slideshow in windows).
  2. Receive measured data from USB device. This resulting data is dependent of a previous step as the test is being executed on a human being.
  3. Do some data analysis.
  4. Plot analyzed data.

As you can see that's a lot of work to do in a single thread. That's why i decided to put a little bit more effort and make this tasks execute "concurrently". But i realized it's not that easy and that's why i'm here.

My thought was to potentially have the following threads/parts:

  1. GUI thread for manipulating user interface. This would be primary thread as well.
  2. Thread which would take care of making an image slideshow.
  3. Thread for listening to a data on a USB port.
  4. Thread for analyzing data.
  5. Thread for plotting data.

For the italic ones i'm still not quite sure if it is really necessary to place them into a dedicated thread. I was thinking to move them into the first thread, responsible for GUI. I had in mind to have some event handlers in the primary thread in which i could capture data from USB and straightaway analyze it and plot it onto the canvas. Analysis shouldn't be very time consuming.

Also I would use user defined messages (i.e. with PostThreadMessage()) to signalize the GUI from USB thread that the data has arrived and in that way trigger data analysis and plotting.

One more detail that is making me concerned is that slideshow thread. I've read that it's not possible/advisable to change GUI from another thread. So what do you think the solution could be in this case? To put it in the same GUI thread (that seems to me as a overkill for a GUI thread) or again handle it in the main thread with some kind of a event?

So, my question would be what do you generally think about this concept? Is there a better/more flexible/easier way to do it?

Thanks guys,

Adi

P.S. i'm using c++ within C++ Builder 2009 IDE

+3  A: 

You can probably get away with combining 1 & 2, since the slide-show feature is essentially gui oriented anyway.

For #3, you may be able to make do with some kind of asynchronous I/O methodology, so that you don't need to dedicate a polling thread. Not sure if you can do this with USB, but you can certainly get async I/O with serial and network interfaces, so it's worth looking into.

It's probably a good idea to move heavy-weight tasks like 4 & 5 to their own thread. If you aren't doing the analysis and plotting concurrently, maybe one thread for them both. However, you should really consider how much cpu time these activities will need. If the worst-case analyze-and-plot takes much less than half a second, you might even just perform these actions with a call from the gui. Conversely, if there are cases where this will take longer than that, a separate thread is favorable b/c your users won't like a laggy gui.

Just bear in mind that the dark side of threads lies in the inevitable challenge of coordinating them.

JustJeff
Adi
+1  A: 

4 and 5 are definitely good ideas. That being said, avoid using low-level threads unless you absolutely must.

I'd check out Boost and Boost::Thread. Not only does it make your code more portable, but I haven't worked with an easier library for threading.

Xorlev
I have, it's called C# ;)
Byron Whitlock
Ditto the C# recommendation - I've recently finished taking some complex chunks of logic over to threads and was blown away by how easy .Net made it to synchronize them with the GUI.
Andy Dent
I've never used Boost before but i checked it and doesn't seem to me like a good solution. It looks way complicated than it should be. Syntax is somewhat cryptic. But nevertheless thank you for your advice.And guys voting for C#, unfortunatelly that's not an option right now :)
Adi
+2  A: 

A lot of this depends on how much is involved in performing 3 (Do some data analysis.) and 4 (Plot analyzed data.)

My instincts would be:

Definitely have a separate thread for reading the data off the USB. Assuming for a moment that 3 is dependent on reading the data, then I would do 3 in the same thread as reading the data. This will simplify your signaling to the GUI when the data is ready. This also assumes the processing is quick, and won't block the USB port (How is that being read? IO completion ports?). If the processing takes time then you need a separate thread.

Likewise if image slide processing show takes a long time, this should be done in a separate thread. If this can be quickly recalculated depending say in a paint function, I would keep it as part of the main GUI.

There is some overhead with context switch of threads, and for each thread added complexity of signaling. So I would only add a thread to solve blocking of the GUI and the USB port. It may be possible to do all of this in just two threads.

David L Morris
Data analysis is practically the most easiest part of application as it's just including some simple calculations, such as signal averaging. Plotting seems to me work fast enough as it is simple 1D signal visualization. It is done with GDI+ but easily i could translate the class to work with OpenGL i.e.@all I think i'll have a try with 2 threads first. I wouldn't like to play around with synchronizing multiple threads as i don't have much experience with it. If it shows that it doesn't work good/fast enough, i'll have a try with one more thread.
Adi
As a rule of thumb, whenever I'm working with an external system that doesn't support retries, I *never* do anything in the thread that reads data. Read it, post it to a queue for processing, reset the interface or ACK the message then wait for the next one. That way I can schedule that thread at a higher priority so it's less likely that it won't be able to respond when a message comes in, but I won't tie up the machine any longer than possible.
TMN
@TMN I agree with your general observation, and would certainly do it the way you suggest if reading a port directly. However, the OS (windows?) is usually doing its own buffering on the input stream, with the driver effectively a separate thread a dedicated thread might be overkill.
David L Morris
+1  A: 

If you are using Builder 2009, you should look at TThread. It has some stuff to simplify thread coding.

gbrandt
Yes, i know about it but it doesn't seem to me like a flexible/worked out solution. But thanks anyway :)
Adi
+3  A: 

Because of the way the Windows API works, especially with regard to user input and window ownership. You can really only do UI on a single thread. If you try and use multiple threads, they just end up locking each other out and only 1 thread runs at a time. There are some specialized exceptions, but you have to be a real master of the API to pull it off.

So.

  1. GUI thread, owns the Window, and handles all user input.
  2. USB listening thread, you would know better than I whether this makes sense
  3. Thread(s) for analyzing/plotting data, once again, I can't speak to this, but I'm skeptical that they will really both be running at the same time. It seems more likely this it would be analyze then plot so 1 thread.
  4. Thread for rendering frames for a slideshow.

I'm not sure how plotting isn't the same thing as the slideshow, but I do think you can have a background thread for drawing the slideshow as long as it doesn't display the images. You can render (i.e. draw to a bitmap or DirectX surface) in a background thread, you just can't show it in a window. But you could hand completed bitmaps off to the GUI thread and have it do the actual displaying of the bitmap. This is essentially how a lot of video playback code works.

John Knoeller
Hm, good advice on having a background thread. But i'm still not very comfortable with passing the parameters/variables between the threads. I'll have a look at it. Thanks.
Adi
+1  A: 

I can't help thinking that you may be going a bit overboard here. A USB port can't really deliver data terribly quickly -- it's theoretical bandwidth is only 480 Mbits/second, and realistically, it's a pretty rare USB device that can really get very close to that.

Unless the analysis you've mentioned is quite a bit more complex than you've implied, my guess is that a single thread is probably entirely adequate. I'd think hard about using overlapped I/O to read the data, and MsgWaitForMultipleObjects for the main message loop.

It seems to me that the main place you stand a good chance of gaining a lot is in plotting the data after it's processed. It might be worth considering something like OpenGL or DirectX Graphics to do the drawing. Especially if you're producing quite a bit of output, this can give a really substantial speed improvement. In an ideal situation, multiple threads might multiply your speed by the number of available cores -- typically 2 or 4 on today's machines. Drawing the output is likely to be the slowest part of the job, and hardware acceleration can easily speed that up by a considerably larger factor -- 10x is at the low end of what you can typically expect, and 100x is fairly common.

Jerry Coffin
I'm still not familiar with overlapped I/O so if you could recommend a good book or article i would be grateful. Or if you want to say something briefly about the concept. Thanks
Adi
The basic idea of overlapped I/O is that when you all ReadFile (for example) it returns immediately, but you also pass it the handle to an Event, and when the read actually completes, the Event is signaled. If you're waiting on that even in your `MsgWaitForMultipleObjects` loop, it'll return and let you know there's some input to process. You process it, and then wait for another even or message.
Jerry Coffin