Thread synchronization

I

Ivan

Hi there

My work on threads continues with more or less success. Here is what I'm
trying to do:
Class JobAgent is incharged for some tasks and when it's called it starts
thread which performs the job. Application contains one list of agents
that are idle at the moment and list of busy agents. In loop it checks if
there
are agents in idle list and if there are some, it starts them.

I'm using events from JobAgent class to notify main thread in order to
update
lists. Problem is that I'm not sure that I use locks at right places and I
have
a problem to understand what it is happening when of the threads fire event
and
code in main thread is called (agent thread is interrupting main thread and
start
execution of event handler - fogy at the moment). Am I missing
synchronization
in that context?

Thx. in advance

Best regards
Ivan



using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Threading;
using System.Diagnostics;

namespace Threads
{
/// <summary>
/// Summary description for Form1.
/// </summary>
public class frmMain : System.Windows.Forms.Form
{
private System.Windows.Forms.Button btnStartThreads;

protected ArrayList idleAgents = new ArrayList ();
protected ArrayList busyAgents = new ArrayList ();

/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.Container components = null;

public frmMain()
{
InitializeComponent();
}

/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}

#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.btnStartThreads = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// btnStartThreads
//
this.btnStartThreads.Location = new System.Drawing.Point(48, 48);
this.btnStartThreads.Name = "btnStartThreads";
this.btnStartThreads.Size = new System.Drawing.Size(88, 23);
this.btnStartThreads.TabIndex = 0;
this.btnStartThreads.Text = "&Start threads";
this.btnStartThreads.Click += new
System.EventHandler(this.btnStartThreads_Click);
//
// frmMain
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(176, 125);
this.Controls.Add(this.btnStartThreads);
this.Name = "frmMain";
this.Text = "Thread test";
this.ResumeLayout(false);

}
#endregion

/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.Run(new frmMain());
}

private void btnStartThreads_Click(object sender, System.EventArgs e)
{
// create job agents and put them in idleAgents list
for (int c = 0;c < 5;c++)
{
JobAgent agent = new JobAgent ();
agent.AgentFinished +=new
JobAgentNotificationEventHandler(agent_AgentFinished);
agent.AgentStarted +=new
JobAgentNotificationEventHandler(agent_AgentStarted);
idleAgents.Add (agent);
}
// check if there are agents in idleAgents list and start them
while (true)
{
if (idleAgents.Count > 0)
((JobAgent)idleAgents[0]).Start ();
}
}

// called when agent finished
private void agent_AgentFinished(JobAgent jobAgent)
{
// move agent from busyAgents in to idleAgents
busyAgents.Remove (jobAgent);
idleAgents.Add (jobAgent);
}

// called when agent started
private void agent_AgentStarted(JobAgent jobAgent)
{
// move agent from idleAgents in to busyAgents
busyAgents.Add (jobAgent);
idleAgents.Remove (jobAgent);
}
}

public delegate void JobAgentNotificationEventHandler (JobAgent jobAgent);

public class JobAgent
{
private bool isBusy = false;
private Object busyLock = new Object ();
private static Object eventLock = new Object ();

protected Thread thread = null;
public event JobAgentNotificationEventHandler AgentStarted = null;
public event JobAgentNotificationEventHandler AgentFinished = null;

public void Start ()
{
lock (busyLock)
{
if (isBusy == true)
return;
else
isBusy = true;
}
thread = new Thread (new ThreadStart (this.Run));
thread.Start ();
// fire event that thread is starting
lock (eventLock)
{
if (AgentStarted != null)
AgentStarted (this);
}
}

public void Run ()
{
Random rnd = new Random ();

Debug.WriteLine ("Thread num. " + Convert.ToString
(Thread.CurrentThread.GetHashCode ()) + " started");
Thread.Sleep (2000 + rnd.Next (5)*1000);
Debug.WriteLine ("Thread num. " + Convert.ToString
(Thread.CurrentThread.GetHashCode ()) + " finished");
lock (busyLock)
{
isBusy = false;
}
lock (eventLock)
{
if (AgentFinished != null)
AgentFinished (this);
}
}
}
}
 
G

Guest

You sound like one of these people that thinks threading is the be-all and end-all of programming, and you're so excited by it that you write the threading part of your application before any other, only to get bored when it doesn't make it go like lightning and solve all your problems. Multithreading ISN'T cool when you don't use it properly, and it won't wave a magic wand to speed up your program. Concentrate on the basics and put in multithreading when you really need it.


Ivan said:
Hi there

My work on threads continues with more or less success. Here is what I'm
trying to do:
Class JobAgent is incharged for some tasks and when it's called it starts
thread which performs the job. Application contains one list of agents
that are idle at the moment and list of busy agents. In loop it checks if
there
are agents in idle list and if there are some, it starts them.

I'm using events from JobAgent class to notify main thread in order to
update
lists. Problem is that I'm not sure that I use locks at right places and I
have
a problem to understand what it is happening when of the threads fire event
and
code in main thread is called (agent thread is interrupting main thread and
start
execution of event handler - fogy at the moment). Am I missing
synchronization
in that context?

Thx. in advance

Best regards
Ivan



using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Threading;
using System.Diagnostics;

namespace Threads
{
/// <summary>
/// Summary description for Form1.
/// </summary>
public class frmMain : System.Windows.Forms.Form
{
private System.Windows.Forms.Button btnStartThreads;

protected ArrayList idleAgents = new ArrayList ();
protected ArrayList busyAgents = new ArrayList ();

/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.Container components = null;

public frmMain()
{
InitializeComponent();
}

/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}

#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.btnStartThreads = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// btnStartThreads
//
this.btnStartThreads.Location = new System.Drawing.Point(48, 48);
this.btnStartThreads.Name = "btnStartThreads";
this.btnStartThreads.Size = new System.Drawing.Size(88, 23);
this.btnStartThreads.TabIndex = 0;
this.btnStartThreads.Text = "&Start threads";
this.btnStartThreads.Click += new
System.EventHandler(this.btnStartThreads_Click);
//
// frmMain
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(176, 125);
this.Controls.Add(this.btnStartThreads);
this.Name = "frmMain";
this.Text = "Thread test";
this.ResumeLayout(false);

}
#endregion

/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.Run(new frmMain());
}

private void btnStartThreads_Click(object sender, System.EventArgs e)
{
// create job agents and put them in idleAgents list
for (int c = 0;c < 5;c++)
{
JobAgent agent = new JobAgent ();
agent.AgentFinished +=new
JobAgentNotificationEventHandler(agent_AgentFinished);
agent.AgentStarted +=new
JobAgentNotificationEventHandler(agent_AgentStarted);
idleAgents.Add (agent);
}
// check if there are agents in idleAgents list and start them
while (true)
{
if (idleAgents.Count > 0)
((JobAgent)idleAgents[0]).Start ();
}
}

// called when agent finished
private void agent_AgentFinished(JobAgent jobAgent)
{
// move agent from busyAgents in to idleAgents
busyAgents.Remove (jobAgent);
idleAgents.Add (jobAgent);
}

// called when agent started
private void agent_AgentStarted(JobAgent jobAgent)
{
// move agent from idleAgents in to busyAgents
busyAgents.Add (jobAgent);
idleAgents.Remove (jobAgent);
}
}

public delegate void JobAgentNotificationEventHandler (JobAgent jobAgent);

public class JobAgent
{
private bool isBusy = false;
private Object busyLock = new Object ();
private static Object eventLock = new Object ();

protected Thread thread = null;
public event JobAgentNotificationEventHandler AgentStarted = null;
public event JobAgentNotificationEventHandler AgentFinished = null;

public void Start ()
{
lock (busyLock)
{
if (isBusy == true)
return;
else
isBusy = true;
}
thread = new Thread (new ThreadStart (this.Run));
thread.Start ();
// fire event that thread is starting
lock (eventLock)
{
if (AgentStarted != null)
AgentStarted (this);
}
}

public void Run ()
{
Random rnd = new Random ();

Debug.WriteLine ("Thread num. " + Convert.ToString
(Thread.CurrentThread.GetHashCode ()) + " started");
Thread.Sleep (2000 + rnd.Next (5)*1000);
Debug.WriteLine ("Thread num. " + Convert.ToString
(Thread.CurrentThread.GetHashCode ()) + " finished");
lock (busyLock)
{
isBusy = false;
}
lock (eventLock)
{
if (AgentFinished != null)
AgentFinished (this);
}
}
}
}
 
I

Ivan

Aren't you a funny girl :)

I am working on bigger project, and this example is only an illustration of
particular problem that I need to handle.

BR
Ivan

Beeeeeeeeeeeeves said:
You sound like one of these people that thinks threading is the be-all and
end-all of programming, and you're so excited by it that you write the
threading part of your application before any other, only to get bored when
it doesn't make it go like lightning and solve all your problems.
Multithreading ISN'T cool when you don't use it properly, and it won't wave
a magic wand to speed up your program. Concentrate on the basics and put in
multithreading when you really need it.
Ivan said:
Hi there

My work on threads continues with more or less success. Here is what I'm
trying to do:
Class JobAgent is incharged for some tasks and when it's called it starts
thread which performs the job. Application contains one list of agents
that are idle at the moment and list of busy agents. In loop it checks if
there
are agents in idle list and if there are some, it starts them.

I'm using events from JobAgent class to notify main thread in order to
update
lists. Problem is that I'm not sure that I use locks at right places and I
have
a problem to understand what it is happening when of the threads fire event
and
code in main thread is called (agent thread is interrupting main thread and
start
execution of event handler - fogy at the moment). Am I missing
synchronization
in that context?

Thx. in advance

Best regards
Ivan



using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Threading;
using System.Diagnostics;

namespace Threads
{
/// <summary>
/// Summary description for Form1.
/// </summary>
public class frmMain : System.Windows.Forms.Form
{
private System.Windows.Forms.Button btnStartThreads;

protected ArrayList idleAgents = new ArrayList ();
protected ArrayList busyAgents = new ArrayList ();

/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.Container components = null;

public frmMain()
{
InitializeComponent();
}

/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}

#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.btnStartThreads = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// btnStartThreads
//
this.btnStartThreads.Location = new System.Drawing.Point(48, 48);
this.btnStartThreads.Name = "btnStartThreads";
this.btnStartThreads.Size = new System.Drawing.Size(88, 23);
this.btnStartThreads.TabIndex = 0;
this.btnStartThreads.Text = "&Start threads";
this.btnStartThreads.Click += new
System.EventHandler(this.btnStartThreads_Click);
//
// frmMain
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(176, 125);
this.Controls.Add(this.btnStartThreads);
this.Name = "frmMain";
this.Text = "Thread test";
this.ResumeLayout(false);

}
#endregion

/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.Run(new frmMain());
}

private void btnStartThreads_Click(object sender, System.EventArgs e)
{
// create job agents and put them in idleAgents list
for (int c = 0;c < 5;c++)
{
JobAgent agent = new JobAgent ();
agent.AgentFinished +=new
JobAgentNotificationEventHandler(agent_AgentFinished);
agent.AgentStarted +=new
JobAgentNotificationEventHandler(agent_AgentStarted);
idleAgents.Add (agent);
}
// check if there are agents in idleAgents list and start them
while (true)
{
if (idleAgents.Count > 0)
((JobAgent)idleAgents[0]).Start ();
}
}

// called when agent finished
private void agent_AgentFinished(JobAgent jobAgent)
{
// move agent from busyAgents in to idleAgents
busyAgents.Remove (jobAgent);
idleAgents.Add (jobAgent);
}

// called when agent started
private void agent_AgentStarted(JobAgent jobAgent)
{
// move agent from idleAgents in to busyAgents
busyAgents.Add (jobAgent);
idleAgents.Remove (jobAgent);
}
}

public delegate void JobAgentNotificationEventHandler (JobAgent jobAgent);

public class JobAgent
{
private bool isBusy = false;
private Object busyLock = new Object ();
private static Object eventLock = new Object ();

protected Thread thread = null;
public event JobAgentNotificationEventHandler AgentStarted = null;
public event JobAgentNotificationEventHandler AgentFinished = null;

public void Start ()
{
lock (busyLock)
{
if (isBusy == true)
return;
else
isBusy = true;
}
thread = new Thread (new ThreadStart (this.Run));
thread.Start ();
// fire event that thread is starting
lock (eventLock)
{
if (AgentStarted != null)
AgentStarted (this);
}
}

public void Run ()
{
Random rnd = new Random ();

Debug.WriteLine ("Thread num. " + Convert.ToString
(Thread.CurrentThread.GetHashCode ()) + " started");
Thread.Sleep (2000 + rnd.Next (5)*1000);
Debug.WriteLine ("Thread num. " + Convert.ToString
(Thread.CurrentThread.GetHashCode ()) + " finished");
lock (busyLock)
{
isBusy = false;
}
lock (eventLock)
{
if (AgentFinished != null)
AgentFinished (this);
}
}
}
}
 
K

Ken Kolda

Ivan --

You've got a number of issues here and it also sounds like you've got some
misunderstanding of how threading works. For example, it's important that
you understand taht when your JobAgent fires it's AgentFinished event, the
call is made on the current thread -- it does not interrupt the main thread.
So, the agent_AgentFinished event handler in frmMain will run in a separate
thread as the btnStartThreads_Click method.

That means multiple threads will be accessing the busyAgents and idleAgents
collections concurrently. So, you need to protect them with locking. Also,
you've tried to implement a means of waiting for the agents to complete by
using an endless while loop that continuously polls the idleAgents
collection -- that's a bad design which will lead to 100% CPU utilization
and your app will be unusable. Instead you need to use signalling between
your threads so your main thread can sleep while waiting for the agents to
do their work. Do some reading on events (see the ManualResetEvent class)
and the Monitor class's Wait and Pulse methods.

I know that's not very detailed, but it should point you in the right
direction.

Good luck -
Ken


Ivan said:
Hi there

My work on threads continues with more or less success. Here is what I'm
trying to do:
Class JobAgent is incharged for some tasks and when it's called it starts
thread which performs the job. Application contains one list of agents
that are idle at the moment and list of busy agents. In loop it checks if
there
are agents in idle list and if there are some, it starts them.

I'm using events from JobAgent class to notify main thread in order to
update
lists. Problem is that I'm not sure that I use locks at right places and I
have
a problem to understand what it is happening when of the threads fire event
and
code in main thread is called (agent thread is interrupting main thread and
start
execution of event handler - fogy at the moment). Am I missing
synchronization
in that context?

Thx. in advance

Best regards
Ivan



using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Threading;
using System.Diagnostics;

namespace Threads
{
/// <summary>
/// Summary description for Form1.
/// </summary>
public class frmMain : System.Windows.Forms.Form
{
private System.Windows.Forms.Button btnStartThreads;

protected ArrayList idleAgents = new ArrayList ();
protected ArrayList busyAgents = new ArrayList ();

/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.Container components = null;

public frmMain()
{
InitializeComponent();
}

/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}

#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.btnStartThreads = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// btnStartThreads
//
this.btnStartThreads.Location = new System.Drawing.Point(48, 48);
this.btnStartThreads.Name = "btnStartThreads";
this.btnStartThreads.Size = new System.Drawing.Size(88, 23);
this.btnStartThreads.TabIndex = 0;
this.btnStartThreads.Text = "&Start threads";
this.btnStartThreads.Click += new
System.EventHandler(this.btnStartThreads_Click);
//
// frmMain
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(176, 125);
this.Controls.Add(this.btnStartThreads);
this.Name = "frmMain";
this.Text = "Thread test";
this.ResumeLayout(false);

}
#endregion

/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.Run(new frmMain());
}

private void btnStartThreads_Click(object sender, System.EventArgs e)
{
// create job agents and put them in idleAgents list
for (int c = 0;c < 5;c++)
{
JobAgent agent = new JobAgent ();
agent.AgentFinished +=new
JobAgentNotificationEventHandler(agent_AgentFinished);
agent.AgentStarted +=new
JobAgentNotificationEventHandler(agent_AgentStarted);
idleAgents.Add (agent);
}
// check if there are agents in idleAgents list and start them
while (true)
{
if (idleAgents.Count > 0)
((JobAgent)idleAgents[0]).Start ();
}
}

// called when agent finished
private void agent_AgentFinished(JobAgent jobAgent)
{
// move agent from busyAgents in to idleAgents
busyAgents.Remove (jobAgent);
idleAgents.Add (jobAgent);
}

// called when agent started
private void agent_AgentStarted(JobAgent jobAgent)
{
// move agent from idleAgents in to busyAgents
busyAgents.Add (jobAgent);
idleAgents.Remove (jobAgent);
}
}

public delegate void JobAgentNotificationEventHandler (JobAgent jobAgent);

public class JobAgent
{
private bool isBusy = false;
private Object busyLock = new Object ();
private static Object eventLock = new Object ();

protected Thread thread = null;
public event JobAgentNotificationEventHandler AgentStarted = null;
public event JobAgentNotificationEventHandler AgentFinished = null;

public void Start ()
{
lock (busyLock)
{
if (isBusy == true)
return;
else
isBusy = true;
}
thread = new Thread (new ThreadStart (this.Run));
thread.Start ();
// fire event that thread is starting
lock (eventLock)
{
if (AgentStarted != null)
AgentStarted (this);
}
}

public void Run ()
{
Random rnd = new Random ();

Debug.WriteLine ("Thread num. " + Convert.ToString
(Thread.CurrentThread.GetHashCode ()) + " started");
Thread.Sleep (2000 + rnd.Next (5)*1000);
Debug.WriteLine ("Thread num. " + Convert.ToString
(Thread.CurrentThread.GetHashCode ()) + " finished");
lock (busyLock)
{
isBusy = false;
}
lock (eventLock)
{
if (AgentFinished != null)
AgentFinished (this);
}
}
}
}
 
R

Roy Fine

Beeeeeeeeeeeeves said:
You sound like one of these people that thinks threading is the be-all and
end-all of programming, and you're so excited by it that you write the
threading part of your application before any other, only to get bored when
it doesn't make it go like lightning and solve all your problems.
Multithreading ISN'T cool when you don't use it properly, and it won't wave
a magic wand to speed up your program. Concentrate on the basics and put in
multithreading when you really need it.
good point - fact is, there is no wand!

it is s simple matter to prove that multithreading programs run slower than
single threaded programs. multithreading is never applied to speed up a
process, but maybe to provide the perception of responsiveness.

in a multithreaded application on a single threaded processor, the only
thing that you can do more than one at a time of is wait! you can have
anynumber of threads wating on a blocking socket operation - but only one
thread ever processing data.

regards
roy fine
..
Ivan said:
Hi there

My work on threads continues with more or less success. Here is what I'm
trying to do:
Class JobAgent is incharged for some tasks and when it's called it starts
thread which performs the job. Application contains one list of agents
that are idle at the moment and list of busy agents. In loop it checks if
there
are agents in idle list and if there are some, it starts them.

I'm using events from JobAgent class to notify main thread in order to
update
lists. Problem is that I'm not sure that I use locks at right places and I
have
a problem to understand what it is happening when of the threads fire event
and
code in main thread is called (agent thread is interrupting main thread and
start
execution of event handler - fogy at the moment). Am I missing
synchronization
in that context?

Thx. in advance

Best regards
Ivan



using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Threading;
using System.Diagnostics;

namespace Threads
{
/// <summary>
/// Summary description for Form1.
/// </summary>
public class frmMain : System.Windows.Forms.Form
{
private System.Windows.Forms.Button btnStartThreads;

protected ArrayList idleAgents = new ArrayList ();
protected ArrayList busyAgents = new ArrayList ();

/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.Container components = null;

public frmMain()
{
InitializeComponent();
}

/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}

#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.btnStartThreads = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// btnStartThreads
//
this.btnStartThreads.Location = new System.Drawing.Point(48, 48);
this.btnStartThreads.Name = "btnStartThreads";
this.btnStartThreads.Size = new System.Drawing.Size(88, 23);
this.btnStartThreads.TabIndex = 0;
this.btnStartThreads.Text = "&Start threads";
this.btnStartThreads.Click += new
System.EventHandler(this.btnStartThreads_Click);
//
// frmMain
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(176, 125);
this.Controls.Add(this.btnStartThreads);
this.Name = "frmMain";
this.Text = "Thread test";
this.ResumeLayout(false);

}
#endregion

/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.Run(new frmMain());
}

private void btnStartThreads_Click(object sender, System.EventArgs e)
{
// create job agents and put them in idleAgents list
for (int c = 0;c < 5;c++)
{
JobAgent agent = new JobAgent ();
agent.AgentFinished +=new
JobAgentNotificationEventHandler(agent_AgentFinished);
agent.AgentStarted +=new
JobAgentNotificationEventHandler(agent_AgentStarted);
idleAgents.Add (agent);
}
// check if there are agents in idleAgents list and start them
while (true)
{
if (idleAgents.Count > 0)
((JobAgent)idleAgents[0]).Start ();
}
}

// called when agent finished
private void agent_AgentFinished(JobAgent jobAgent)
{
// move agent from busyAgents in to idleAgents
busyAgents.Remove (jobAgent);
idleAgents.Add (jobAgent);
}

// called when agent started
private void agent_AgentStarted(JobAgent jobAgent)
{
// move agent from idleAgents in to busyAgents
busyAgents.Add (jobAgent);
idleAgents.Remove (jobAgent);
}
}

public delegate void JobAgentNotificationEventHandler (JobAgent jobAgent);

public class JobAgent
{
private bool isBusy = false;
private Object busyLock = new Object ();
private static Object eventLock = new Object ();

protected Thread thread = null;
public event JobAgentNotificationEventHandler AgentStarted = null;
public event JobAgentNotificationEventHandler AgentFinished = null;

public void Start ()
{
lock (busyLock)
{
if (isBusy == true)
return;
else
isBusy = true;
}
thread = new Thread (new ThreadStart (this.Run));
thread.Start ();
// fire event that thread is starting
lock (eventLock)
{
if (AgentStarted != null)
AgentStarted (this);
}
}

public void Run ()
{
Random rnd = new Random ();

Debug.WriteLine ("Thread num. " + Convert.ToString
(Thread.CurrentThread.GetHashCode ()) + " started");
Thread.Sleep (2000 + rnd.Next (5)*1000);
Debug.WriteLine ("Thread num. " + Convert.ToString
(Thread.CurrentThread.GetHashCode ()) + " finished");
lock (busyLock)
{
isBusy = false;
}
lock (eventLock)
{
if (AgentFinished != null)
AgentFinished (this);
}
}
}
}
 
F

Fred Chateau

...
in a multithreaded application on a single threaded processor, the only
thing that you can do more than one at a time of is wait! you can have
anynumber of threads wating on a blocking socket operation - but only one
thread ever processing data.

I was going to bring this up in a new topic, but I thought it might be
somewhat appropriate here. I'm trying to get a better understanding of the
relationship between threading, multicast delegates, and event handlers.

I couldn't help noticing a new thread always begins with a ThreadStart
delegate, and I was wondering if event driven programming then implies a
threading model? In other words, for many cases, it seems to me that an
event handler is not replacing the currently executing code, but rather
providing some kind of background support for it. I can see where exception
handling may benefit from executing specific event driven code in the
primary thread, but even there, you've often got a finally block running
somewhere (presumably in the background).

I guess what I'm basically asking is if when deriving from System.Delegate
and creating event handlers, is threading ever occurring behind-the-scenes
as part of the Framework's base class implementation? So is it necessary to
have threads waiting on a blocking socket operation, or can it be handled
effectively by having one execution thread and a socket operation that fires
events when the socket is available?

I'm not really expecting detailed answers to complicated questions here, but
I was hoping someone might point me to an article or whitepaper on the
subject.

--

Regards,

Fred Chateau
e-mail: fchateauAtComcastDotNet
 
J

Jon Skeet [C# MVP]

Fred Chateau said:
I was going to bring this up in a new topic, but I thought it might be
somewhat appropriate here. I'm trying to get a better understanding of the
relationship between threading, multicast delegates, and event handlers.

I couldn't help noticing a new thread always begins with a ThreadStart
delegate, and I was wondering if event driven programming then implies a
threading model?

Well, there's *always* a threading model present in any application -
code has to run in a thread of some sort!
In other words, for many cases, it seems to me that an
event handler is not replacing the currently executing code, but rather
providing some kind of background support for it. I can see where exception
handling may benefit from executing specific event driven code in the
primary thread, but even there, you've often got a finally block running
somewhere (presumably in the background).

I guess what I'm basically asking is if when deriving from System.Delegate
and creating event handlers, is threading ever occurring behind-the-scenes
as part of the Framework's base class implementation?

No. Events are just a restrictive way of exposing delegates. If you
fire a delegate in the normal way, it executes on the same thread. If
you use BeginInvoke, it executes on a ThreadPool thread asynchronously.
So is it necessary to have threads waiting on a blocking socket
operation, or can it be handled effectively by having one execution
thread and a socket operation that fires events when the socket is
available?

Well, you can use Select to pick a socket which can now be read from or
written to etc, or use asynchronous socket calls. My main point is that
the delegate/event model *in itself* doesn't create any threads, unless
you count the ThreadPool threads used for BeginInvoke. Other APIs can
create threads, etc, of course.
 
F

Fred Chateau

...
No. Events are just a restrictive way of exposing delegates. If you fire a
delegate in the normal way, it executes on the same thread. If you use
BeginInvoke, it executes on a ThreadPool thread asynchronously.

I guess I didn't prepare that question very well, but I think I got my
answer anyway. Thanks . . .

I meant to bring up the subject of asynchronous calls, as they relate to
event handlers, because it was looking at code using them that got me
thinking about this. Why I left that out I don't know. :)

So is it reasonable to say that a good place to start with threading, is
when the situation requires it, to think in terms of implementing
asynchronous event handling, and leave the System.Threading stuff for later?
Or do I still have the same synchronization issues to consider?

--

Regards,

Fred Chateau
e-mail: fchateauAtComcastDotNet
 
J

Jon Skeet [C# MVP]

Fred Chateau said:
So is it reasonable to say that a good place to start with threading, is
when the situation requires it, to think in terms of implementing
asynchronous event handling, and leave the System.Threading stuff for later?
Or do I still have the same synchronization issues to consider?

It entirely depends on what you need to do. You need to have a pretty
clear threading policy, including data access etc, whatever you do
beyond a single thread.

If you haven't already read it, see if
http://www.pobox.com/~skeet/csharp/multithreading.html
helps.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top