Re: .net 2.0 : looking for a "best practice" for multi threading jobs



Hi again,

I'm getting troubles in implementing the producer/consumer pattern for
multiple parralel threads...

Here where I am (a project class)... the code is simplified for better
read...

In some conditions, all threads are "blocked" in the GetNectAction() method
waiting in the Monitor.WaitOne method...

Do you have any idea what is wrong ?
Thanks,
Steve

public class Project
{
#region Properties
private int m_numberOfThreads;
private object m_numberOfThreadsLockObject = new object();
public int NumberOfThreads
{
get
{
lock (m_numberOfThreadsLockObject)
{
return m_numberOfThreads;
}
}
}
private int m_runningThreads = 0;
private object m_runningThreadsLockObject = new object();
public int RunningThreads
{
get
{
lock (m_runningThreadsLockObject)
{
return m_runningThreads;
}
}
}
private Exporter m_exporter;
public Exporter Exporter
{
get { return m_exporter; }
}
#region Cancellable worker
private readonly object m_stoppingLockObject = new object();
private bool m_stopping;
public bool Stopping
{
get
{
lock (m_stoppingLockObject)
{
return m_stopping;
}
}
}
private bool m_stopped;
public bool Stopped
{
get
{
lock (m_stoppingLockObject)
{
return m_stopped;
}
}
}
private void SetStopped()
{
Debug.WriteLine("Fin des threads par " + Thread.CurrentThread.Name);
lock (m_numberOfThreadsLockObject)
{
this.m_stopped = true;
}
}
#endregion
private Queue<Action> m_actions;
private object m_actionsLockObject = new object();
protected Queue<Action> Actions
{
get
{
lock (m_actions)
{
return m_actions;
}
}
}
#endregion
public Project(
int numberOfThreads
)
{
this.m_numberOfThreads = numberOfThreads;
this.m_actions = new Queue<Action>();
}
public void Execute()
{
for (int i = 0; i < m_numberOfThreads; i++)
{
lock (m_runningThreadsLockObject)
{
ThreadStart ts = new ThreadStart(WorkerMethod);
Thread t = new Thread(ts);
t.Name = "Thread N°" + i.ToString();
t.Start();
m_runningThreads++;
}
}
AddAction(new DownloadAction(
new Uri("http://myserver/app/rootfile";)
));
}
}
public void AddAction(Action a)
{
Debug.WriteLine("AddAction dans thread " + Thread.CurrentThread.Name);
lock (m_actionsLockObject)
{
Actions.Enqueue(a);
Debug.WriteLine("Monitor.Pulse " + Thread.CurrentThread.Name);
Monitor.Pulse(m_actionsLockObject);
}
}
private Action GetNextAction()
{
lock (m_actionsLockObject)
{
Monitor.Wait(this.m_actionsLockObject);
return Actions.Dequeue();
}
}
private void WorkerMethod()
{
Debug.WriteLine("WorkerMethod dans thread " + Thread.CurrentThread.Name);
Action a;
while (!Stopping && (a = GetNextAction()) != null)
{
a.Execute();
}
lock (m_runningThreadsLockObject)
{
if (--m_runningThreads == 0)
{
SetStopped();
}
}
Debug.WriteLine("Fin du thread " + Thread.CurrentThread.Name);
}
public void Stop()
{
lock (m_actionsLockObject)
{
Monitor.PulseAll(m_actionsLockObject);
}
Debug.WriteLine("Stop dans thread " + Thread.CurrentThread.Name);
lock (m_stoppingLockObject)
{
this.m_stopping = true;
}
}
}


"Michael Nemtsev" <nemtsev@xxxxxxx> a écrit dans le message de news:
1799a79b3d745c8c925a4aeaed6ee@xxxxxxxxxxxxxxxxxxxxxxx
Hello Steve B.,

S> I'm building an application that follow this scenario.
S> 1. Download a file on a server with http
S> 2. Analyse this file and extract other files in one of the section of
S> the
S> file (like dependent files)
S> 3. Foreach found files, repeat the whole process.

S> The question is : how can I quickly and correctly design my code to
S> have my winform dynamic, and the pool of working threads?


S> My first reflexion was to store the whole data in a DataSet (easy
S> databinding) which can be flat (only on DataTable required).

so, you keep serialized objects?! why not to just save files on your
drive?

S> I also created an abstract class "BaseAction" that is inherited by
S> two classes : "DownloadAction" and "AnalyseAction".
S> My process object defines a Queue<Action> where I add all required
S> actions.
S> But I'm confused for the next steps... how can I have multiples
S> trheads that can "Dequeue" actions? moreover, I don't know how to
manage the
S> multiples threeads since sometimes I'll have only one item in te queue,
and
S> this item can add new items...

You can use ThreadPool class (standard .net) or Produce/consummer pattern

http://www.yoda.arachsys.com/csharp/threads/threadpool.shtml
http://groups.google.ru/group/microsoft.public.dotnet.framework/browse_thread/thread/a33378c87b856678/abc251c95cbac487

The idea is that you can dequeue your files and each tread will analyze
your files dequeuing them


---
WBR, Michael Nemtsev [C# MVP]. My blog: http://spaces.live.com/laflour
Team blog: http://devkids.blogspot.com/

"The greatest danger for most of us is not that our aim is too high and we
miss it, but that it is too low and we reach it" (c) Michelangelo




.



Relevant Pages

  • Re: thread-safety
    ... and I started to use dotnet's queue collection with lock protection. ... private enum WorkerThreadState; ... private object stateLocker = new object; ... public void Start ...
    (microsoft.public.dotnet.languages.csharp)
  • Re: thread-safety
    ... It supports immediate addition to the consumer's queue, and creation of a repeating timer that will periodicially add to the consumer's queue. ... private TimeSpan _tsExecute; ... // the JobConsumer class while holding it's own lock. ... public void Add ...
    (microsoft.public.dotnet.languages.csharp)
  • Locking objects in an array
    ... I have a bidimensional array of objects (view it as a 2D lattice). ... Thus I want to lock the 4 objects of the region, ... public void increment{ ... private static final Random rnd = new Random; ...
    (comp.lang.java.programmer)
  • Re: SyncLock documentation
    ... You should declare a Private object variable to ... variable to protect data common to all instances. ... You should not use the Me keyword to provide a lock object for instance ... In the example below, bbb uses 'synclock me', and ccc uses 'synclock sss' ...
    (microsoft.public.dotnet.languages.vb)
  • Re: lock statement question
    ... I have a private timer member whose interval can be changed by different threads. ... When you lock on an object, it doesn't protect the object itself from access in any way, it only prevents other threads to enter any code that is locked using the same object. ... They use the same object for locking, so while some thread is using one of the methods, no other thread can use any of the two methods. ...
    (microsoft.public.dotnet.languages.csharp)