4

I am new to multithreading and have designed a program that receives data from two microcontroller measuring various temperatures (Ambient and Water) and draws the data to the screen. Right now the program is singly threaded and its performance SUCKS A BIG ONE.

I get basic design approaches with multithreading but not well enough to create a thread to do a task but what I don't get is how to get threads to perform seperate task and place the data into a shared data pool. I figured that I need to make a queue that has one consumer and multiple producers (would like to use std::queue). I have seen some code on the gtkmm threading docs that show a single Con/Pro queue and they would lock the queue object produce data and signal the sleeping thread that it is finished then the producer would sleep. For what I need would I need to sleep a thread, would there be data conflicts if i didn't sleep any of the threads, and would sleeping a thread cause a data signifcant data delay (I need realtime data to be drawn 30 frames a sec)

How would I go about coding such a queue using the gtkmm/glibmm library.

Talguy
  • 1,045
  • 2
  • 18
  • 27

2 Answers2

2

If you're looking for a lock free implementation of this, you won't find one. When data structures are being written to, something needs to keep two threads from simultaneously updating the data structure and corrupting it.

Is there any reason you can't have each thread collect on it's own, with it's own structure, and then combine the results at the end?

Billy ONeal
  • 104,103
  • 58
  • 317
  • 552
  • 1
    Each thread would be communicating with the a single uC and would process the data and package it to be drawn to the screen. Would a locking system be easier to implement, not really sure how to implement what you described – Talguy Apr 28 '10 at 16:40
  • @Talguy: What is a uC? If you mean microsecond, and you're trying to update the display every microsecond, then no amount of multithreading is going to help you. Displays don't update that fast; you'd be better off using polling in that scenario instead. – Billy ONeal Apr 28 '10 at 16:58
  • uC = microcontroller. Sorry for the confusion – Talguy Apr 28 '10 at 17:00
  • @Talguy: No problem (abbreviations are perfectly acceptable in comments because they have length limits) If that's the case I would still recommend a polling solution. I.e. the display updates itself once every so often (say, once every 50-100ms should be enough for most purposes). Then there need not be a common set of data between the worker threads, and the UI only needs read access to those threads. – Billy ONeal Apr 28 '10 at 17:02
  • I got what your saying. I'm going to go with a dedicated circular buffer like Thomas Matthews suggested – Talguy Apr 28 '10 at 17:46
  • Using linked lists, it's possible to create a lock-free multiple-producer single-consumer queue. The simplest way is to use Interlocked.CompareExchange make a multiple-producer stack which supports thread-safe Push and PopAll methods. The Push method will grab the head reference, copy it to the new item's "next" reference, and CompareExchange the head to the new item if it hasn't changed. The PopAll method will Exchange the head reference with a null reference and return the old value. – supercat Mar 14 '11 at 19:47
  • To make a multi-producer single-consumer queue, use two such stacks. Data is pushed into the first one; only the reader thread will access the second. To dequeue data, check if the second stack is empty. If not, just pop an item. Otherwise, use firstStack.PopAll to make a copy of the first stack, and then push all the items onto the second stack. If many items are enqueued before a dequeue operation, this reversal process may take some time, but every item will have to be copied exactly once regardless of whether the copy operations follow individual enqueue operations or occur as a group. – supercat Mar 14 '11 at 19:54
2

Here's a suggestion:
1. Have two threads, that are responsible for obtaining data and placing into a buffer. Each thread has it's own (circular) buffer.
2. There will be a third thread that is responsible for getting data from the buffers and displaying on the screen.
3. The screen thread sends messages to the data threads requesting some data, then displays the data. The messages help synchronize execution and avoid dead-locks.
4. None of the threads should "wait on single or multiple objects", but poll for events.

Think of this scenario using people. One person is delivering water temperature readings. Another person delivering ambient temperature readings. A third person receives or asks for the data and displays the data (on a white board). The objective is to keep everybody operating at maximum efficiency without any collisions.

Thomas Matthews
  • 56,849
  • 17
  • 98
  • 154
  • To have the GUI thread read from each circular buffer I would have the worker thread supply the gui thread with a pointer to the position of he oldest data object in the buffer and the worker thread would just automatically updated the oldest item in the buffer? – Talguy Apr 28 '10 at 16:59
  • No, "don't cross the streams." The worker threads will provide methods for accessing the data. This isolates the data structure from the GUI thread and also prevents headaches with data sharing between tasks. The worker knows the structure of his inventory. Let him give you what you ask for; don't mess with his filing system. ;-) – Thomas Matthews Apr 28 '10 at 23:26
  • This is the defiantly the best way to accomplish what I want I am just a little confused on how to implement that link between the gui and worker. The way I am seeing it is that I have an instance of my hardware object in the main thread. HWobj worker thread is launched. HWobj has a method called pop_front() that returns and removes the front item of the circlular queue. When ever the main method calls pop it would get the oldest item left. If this is the right way there would still be a little bit of locking when reading data from the buffer? – Talguy Apr 29 '10 at 18:13