[Mono-devel-list] Re: Threading model
Rafael Teixeira
monoman at gmail.com
Fri Aug 5 14:00:55 EDT 2005
Hi Paul,
First, from msdn:
Note There are four methods on a control that are safe to call from
any thread: Invoke, BeginInvoke, EndInvoke, and CreateGraphics. For
all other method calls, you should use one of the invoke methods to
marshal the call to the control's thread.
See: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfsystemwindowsformscontrolclassinvoketopic.asp
and
http://msdn.microsoft.com/library/en-us/cpref/html/frlrfSystemWindowsFormsControlClassInvokeRequiredTopic.asp?frame=true
This modified version of your ugly program runs for a while (hundreds
of increments):
<code>
using System;
using System.Threading;
using System.Windows.Forms;
using System.Drawing;
public class Sharing1 : Form
{
private TextBox accessCountBox = new TextBox();
private Button start = new Button();
private Button watch = new Button();
private int accessCount = 0;
public void incrementAccess()
{
accessCount++;
UpdateAccess();
}
public void UpdateAccess()
{
if (!accessCountBox.InvokeRequired)
accessCountBox.Text = accessCount.ToString();
else
accessCountBox.BeginInvoke(new MethodInvoker(UpdateAccess));
}
private int numCounters = 12;
private int numWatchers = 15;
private TwoCounter[] s;
public Sharing1()
{
ClientSize = new Size(450, 480);
Panel p = new Panel();
p.Size = new Size(400, 50);
start.Click += new EventHandler(StartAllThreads);
watch.Click += new EventHandler(StartAllWatchers);
accessCountBox.Text = "0";
accessCountBox.Location = new Point(10, 10);
start.Text = "Start threads";
start.Location = new Point(110, 10);
start.Width = 80;
watch.Text = "Begin watching";
watch.Location = new Point(210, 10);
watch.Width = 180;
p.Controls.Add(start);
p.Controls.Add(watch);
p.Controls.Add(accessCountBox);
s = new TwoCounter[numCounters];
for (int i = 0; i < s.Length; i++)
{
s[i] = new TwoCounter(new TwoCounter.IncrementAccess(incrementAccess));
s[i].Location = new Point(10, 50 + s[i].Height * i);
Controls.Add(s[i]);
}
this.Closed += new EventHandler(StopAllThreads);
Controls.Add(p);
}
public void StartAllThreads(object sender, EventArgs ea)
{
for (int i = 0; i < s.Length; i++)
s[i].Start();
}
public void StopAllThreads(object sender, EventArgs ea)
{
for (int i = 0; i < s.Length; i++)
if (s[i] != null)
s[i].Stop();
}
public void StartAllWatchers(object sender, EventArgs ea)
{
for (int i = 0; i < numWatchers; i++)
new Watcher(s);
}
public static void Main(string [] args)
{
Sharing1 app = new Sharing1();
if (args.Length > 0)
{
app.numCounters = SByte.Parse(args[0]);
if (args.Length == 2)
app.numCounters = SByte.Parse(args[1]);
}
Application.Run(app);
}
}
class TwoCounter : Panel
{
private bool started = false;
private Label t1;
private Label t2;
private Label lbl;
private Thread t;
private int count1 = 0, count2 = 0;
public delegate void IncrementAccess();
IncrementAccess del;
public TwoCounter(IncrementAccess del)
{
this.del = del;
this.Size = new Size(350, 30);
this.BorderStyle = BorderStyle.Fixed3D;
t1 = new Label();
t1.Location = new Point(10, 10);
t2 = new Label();
t2.Location = new Point(110, 10);
lbl = new Label();
lbl.Location = new Point(210, 10);
lbl.Text = "Count1 == Count2";
Controls.AddRange(new Control[] {t1, t2, lbl} );
t = new Thread(new ThreadStart(run));
}
public void Start()
{
if (!started)
{
started = true;
t.Start();
}
}
public void Stop()
{
t.Abort();
}
public void run()
{
while(true)
{
UpdateLabels();
Thread.Sleep(500);
}
}
public void synchTest()
{
del();
if (count1 != count2)
UpdateSynch();
}
private void UpdateLabels()
{
if (!t1.InvokeRequired) {
t1.Text = (++count1).ToString();
t2.Text = (++count2).ToString();
} else // Will be queued for execution in the UI Thread
t1.BeginInvoke(new MethodInvoker(UpdateLabels));
}
private void UpdateSynch()
{
if (!lbl.InvokeRequired)
lbl.Text = "Unsynched";
else // Will be queued for execution in the UI Thread
lbl.BeginInvoke(new MethodInvoker(UpdateSynch));
}
}
class Watcher
{
TwoCounter[] s;
public Watcher(TwoCounter[] s)
{
this.s = s;
new Thread(new ThreadStart(run)).Start();
}
public void run()
{
while(true)
{
for(int i = 0; i < s.Length; i++)
s[i].synchTest();
Thread.Sleep(500);
}
}
}
</code>
Probably some error on locking/freeing threads is generating this exception
<exception>
Unhandled Exception: System.ObjectDisposedException: The object was
used after being disposed.
in [0x0002d] System.Threading.WaitHandle:CheckDisposed ()
in [0x00001] (at mcs/class/corlib/System.Threading/WaitHandle.cs:177)
System.Threading.WaitHandle:WaitOne ()
in [0x0000e] (at
mcs/class/Managed.Windows.Forms/System.Windows.Forms/AsyncMethodResult.cs:78)
System.Windows.Forms.AsyncMethodResult:Complete (System.Object result)
in [0x00062] (at
mcs/class/Managed.Windows.Forms/System.Windows.Forms/XplatUIDriver.cs:279)
System.Windows.Forms.XplatUIDriverSupport:ExecuteClientMessage
(GCHandle gchandle)
in [0x00a8c] (at
mcs/class/Managed.Windows.Forms/System.Windows.Forms/XplatUIX11.cs:2536)
System.Windows.Forms.XplatUIX11:GetMessage (System.Windows.Forms.MSG
msg, IntPtr handle, Int32 wFilterMin, Int32 wFilterMax)
in [0x00009] (at
mcs/class/Managed.Windows.Forms/System.Windows.Forms/XplatUI.cs:440)
System.Windows.Forms.XplatUI:GetMessage (System.Windows.Forms.MSG msg,
IntPtr hWnd, Int32 wFilterMin, Int32 wFilterMax)
in [0x0012e] (at
mcs/class/Managed.Windows.Forms/System.Windows.Forms/Application.cs:365)
System.Windows.Forms.Application:Run ()
in [0x0004a] (at
mcs/class/Managed.Windows.Forms/System.Windows.Forms/Application.cs:388)
System.Windows.Forms.Application:Run
(System.Windows.Forms.ApplicationContext context)
in [0x0000c] (at
mcs/class/Managed.Windows.Forms/System.Windows.Forms/Application.cs:379)
System.Windows.Forms.Application:Run (System.Windows.Forms.Form
mainForm)
in <0x000b8> Sharing1:Main (System.String[] args)
</exception>
Hope it helps,
--
Rafael "Monoman" Teixeira
---------------------------------------
I'm trying to become a "Rosh Gadol" before my own eyes.
See http://www.joelonsoftware.com/items/2004/12/06.html for enlightment.
It hurts!
More information about the Mono-devel-list
mailing list