By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
431,852 Members | 2,123 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 431,852 IT Pros & Developers. It's quick & easy.

Can a separate thread own a form control?

P: n/a
Basically what I have is a form with a graph on it which graphs data
that I'm reading from a USB device at 100 Hz (every 10ms). I have a
thread reading and parsing the data from the USB, but when it comes
time to draw that data on the graph the work is handled on the main UI
thread through a callback delegate since the form owns the graph
control. Is there a way I can have a separate thread own the graph
control and handle the drawing so that the rest of the UI is not
affected?

Thanks in advance,
Stu
Nov 18 '08 #1
Share this Question
Share on Google+
3 Replies


P: n/a
On Tue, 18 Nov 2008 09:09:55 -0800, <st*******@gmail.comwrote:
Basically what I have is a form with a graph on it which graphs data
that I'm reading from a USB device at 100 Hz (every 10ms). I have a
thread reading and parsing the data from the USB, but when it comes
time to draw that data on the graph the work is handled on the main UI
thread through a callback delegate since the form owns the graph
control. Is there a way I can have a separate thread own the graph
control and handle the drawing so that the rest of the UI is not
affected?
What do you mean by "not affected"? In what way is "the rest of the UI"
being affected by your graphing that you believe would be addressed by
moving the graphing to a different thread?

The short answer is: yes, you can create your graphing control on a
different thread, and as long as you provide a message pump on that
thread, it should work fine.

But I fail to see the advantage in doing so. It would be helpful if you
could be more specific about what problem it is you perceive and which you
want to solve.

Pete
Nov 18 '08 #2

P: n/a
This is obviously a trimmed down version of the whole thing, but
should show you what I'm doing. ProcessUsbData is the thread which
reads in the data and calls the functions to update the graph and
textboxes. If I take out the UpdateO2Textbox(O2) and UpdateCO2Textbox
(CO2) calls then the symptoms I'm seeing crop up. By the way, please
feel free to let me know if any of my code sucks and could be done in
a more efficient manner. For instance, if I'm supposed to be reading
from a USB once every 10 seconds is there a better way to do it than
doing Thread.Sleep(10) and then checking the inbound buffer? Thanks
again!
You don't need Thread.Sleep, because ReadLine should efficiently wait until
data is available.

bAbortRead should be volatile, because it changes from a different thread
than is reading it, with no synchronization.

You're making four cross-thread calls every time which is hurting
performance. And you should use MethodInvoker for maximum performance. Try
this:

volatile bool bAbortRead; // bool fields are initialized to false
by the compiler
private void ProcessUsbData()
{
string[] data;
DateTime startTime = DateTime.Now;

while(!bAbortRead)
{
data = device.ReadLine().Split(new char[]{','});

decimal ts = (DateTime.Now - startTime).TotalSeconds;

decimal O2 = 0;
if(data.Length O2INDEX)
decimal.TryParse(data[O2INDEX], out O2);

decimal CO2 = 0;
if(data.Length CO2INDEX)
decimal.TryParse(data[CO2INDEX], out CO2);

MethodInvoker updateGUI = delegate {
if(O2 0 && O2 < 100)
{
AddDataPoint("O2", ts, O2);
UpdateO2Textbox(O2);
}
if(CO2 0 && CO2 < 100)
{
AddDataPoint("CO2", ts, CO2);
UpdateCO2Textbox(CO2);
}
};

if (InvokeRequired)
Invoke(updateGUI);
else
updateGUI();
}
}

>
public partial class frmSampleForm : Form
{
private bool bAbortRead;

Thread BufferReader;
delegate void AddDataPointCallback(string series, decimal x,
decimal y);
delegate void UpdateO2TextboxCallback(decimal pValue);
delegate void UpdateCO2TextboxCallback(decimal pValue);

public frmTesting_VerifySetup(ref cExercise_Test pTest)
{
InitializeComponent();

ReadUSB();
}

private void ReadUSB()
{
// Start the thread which reads the inbound buffer
bAbortRead = false;
BufferReader = new Thread(new ThreadStart(ProcessUsbData));
BufferReader.Start();
}

private void ProcessUsbData()
{
string[] data;
decimal O2;
decimal CO2;
TimeSpan ts;
DateTime startTime = DateTime.Now;

while(!bAbortRead)
{
data = device.ReadLine().Split(new char[]{','});

if(data.Length O2INDEX)
decimal.TryParse(data[O2INDEX], out O2);
else
O2 = 0;

if(data.Length CO2INDEX)
decimal.TryParse(data[CO2INDEX], out CO2);
else
CO2 = 0;

ts = DateTime.Now - startTime;
if(O2 0 && O2 < 100)
{
AddDataPoint("O2", (decimal)(ts.TotalSeconds),
O2);
UpdateO2Textbox(O2);
}
if(CO2 0 && CO2 < 100)
{
AddDataPoint("CO2", (decimal)(ts.TotalSeconds),
CO2);
UpdateCO2Textbox(CO2);
}

Thread.Sleep(10);
}
}

private void AddDataPoint(string series, decimal x, decimal y)
{
// InvokeRequired required compares the thread ID of the
// calling thread to the thread ID of the creating thread.
// If these threads are different, it returns true.
if(chart1.InvokeRequired)
{
AddDataPointCallback d = new AddDataPointCallback
(AddDataPoint);
Invoke(d, new object[] { series, x, y });
}
else
{
chart1.Series[series].Points.AddXY(x, y);
chart1.Invalidate();
}
}

private void UpdateO2Textbox(decimal pValue)
{
// InvokeRequired required compares the thread ID of the
// calling thread to the thread ID of the creating thread.
// If these threads are different, it returns true.
if(txtO2.InvokeRequired)
{
UpdateO2TextboxCallback d = new
UpdateO2TextboxCallback (UpdateO2Textbox);
Invoke(d, new object[] { pValue });
}
else
{
txtO2.Text = pValue.ToString("0.00");
}
}

private void UpdateCO2Textbox(decimal pValue)
{
// InvokeRequired required compares the thread ID of the
// calling thread to the thread ID of the creating thread.
// If these threads are different, it returns true.
if(txtCO2.InvokeRequired)
{
UpdateCO2TextboxCallback d = new
UpdateCO2TextboxCallback(UpdateCO2Textbox);
Invoke(d, new object[] { pValue });
}
else
{
txtCO2.Text = pValue.ToString("0.00");
}
}

}

Nov 19 '08 #3

P: n/a
On Tue, 18 Nov 2008 09:09:55 -0800 (PST), st*******@gmail.com wrote:
>Basically what I have is a form with a graph on it which graphs data
that I'm reading from a USB device at 100 Hz (every 10ms). I have a
thread reading and parsing the data from the USB, but when it comes
time to draw that data on the graph the work is handled on the main UI
thread through a callback delegate since the form owns the graph
control. Is there a way I can have a separate thread own the graph
control and handle the drawing so that the rest of the UI is not
affected?
Having followed the thread these thoughts come to mind. The issue
seems to be the side effects of trying to maintain the data display in
real-time. I recently ran into a similar issue writing a CAT
controller/monitor for a device with minimal documentation.
http://www.subdevo.com/FT897DCAT/

The device has thirteen buttons, seven rotary controls (three
concentric plus one), six LEDs and a ~2x3 inch LCD screen. All the
controls are multifunction. One of the things the LCD display can do
is act as a spectrum scope. This gives an idea of how much and the
kind of information the UI might be expected to display.

Each request/response pair exchanged describes part of the current or
desired state of the device. The state information is sent to the
device using five byte requests. Depending upon the request the
response may be zero to five bytes with a RTT of up to ~5 ms. Multiple
requests are needed to fully describe the device's state. At any time
the polling may be interrupted to send a request to the device to
change state.

Trying to update the numerous UI controls in real-time resulted in a
sluggish UI. My solution was to create an type which represents the
device's state to the UI. It is a composite object that essentially is
a middle tier between the device and UI. A worker thread (the
controller thread) runs a loop that manages various custom thread
objects. The callbacks go to the worker thread not the UI thread. Each
polled response partially updates the state.

This scheme lets the BL/TL/device wrappers to be packaged UI-free. A
timer in the UI fires periodically to update numerous UI controls with
data read from properties the clean, simple interface the state object
presents to the UI.. Changes to the device state are made from the UI
by changing state object's properties.

regards
A.G.



Nov 20 '08 #4

This discussion thread is closed

Replies have been disabled for this discussion.