Hi all C# gurus I need advice on Deadlock
I have a code structure for Window Service, multithreading, task factory like
public partial class rs : ServiceBase
{
private Queue jobQueue = Queue.Synchronized(new Queue());
private Queue DatafeedQueue = Queue.Synchronized(new Queue());
private Dictionary<...> ScheduleJobs = new Dictionary<...>();
private AutoResetEvent _BlockThreadTaskScheduler = new AutoResetEvent(true);
private AutoResetEvent _BlockThreadDatafeedSourceTaskScheduler = new AutoResetEvent(false);
private LimitedConcurrencyLevelTaskScheduler _TaskScheduler;
private LimitedConcurrencyLevelTaskScheduler _DatafeedSourceTaskScheduler;
public rs()
{
InitializeComponent();
_timer = new System.Timers.Timer(POLL_INTERVAL_MINUTE * 60 * 1000);
_timer.Elapsed += new System.Timers.ElapsedEventHandler(_timer_Elapsed);
_TaskScheduler = new LimitedConcurrencyLevelTaskScheduler(2);
_DatafeedSourceTaskScheduler = new LimitedConcurrencyLevelTaskScheduler(1);
protected void _timer_Elapsed(object sender, ElapsedEventArgs e)
{
try
{
DatafeedQueue.Clear();
try
{
(Execute a stored procedure here)
while(xxx.Read())
{
DatafeedObj dfo = new DatafeedObj();
...
DatafeedQueue.Enqueue(dfo);
}
}
catch()...
TaskFactory DatafeedSourceFactory = new TaskFactory(_DatafeedSourceTaskScheduler);
// DatafeedQueue.Count = 3
for (int i = 0; i < DatafeedQueue.Count; i++)
{
DatafeedSourceFactory.StartNew(() => processDatafeedQueue());
}
_BlockThreadDatafeedSourceTaskScheduler.Set();
}
catch()...
}
private void processDatafeedQueue()
{
_BlockThreadDatafeedSourceTaskScheduler.WaitOne();
try
{
lock (DatafeedQueue.SyncRoot)
{
if (DatafeedQueue.Count > 0)
{
DatafeedObj dfo = ((DatafeedObj)(DatafeedQueue.Dequeue()));
#region DataFeed Type A
ScheduleJobs = (Calls a static class, static method);
jobQueue = (Calls a static class, static method turn ScheduleJobs dictionary into Queue);
var factory = new TaskFactory(_TaskScheduler);
for (int i = 0; i < jobQueue.Count; i++)
{
factory.StartNew(() => startTypeA());
}
#endregion
#region DataFeed Type B
ScheduleJobs = (Calls a static class, static method);
jobQueue = (Calls a static class, static method turn ScheduleJobs dictionary into Queue);
var factory = new TaskFactory(_TaskScheduler);
for (int i = 0; i < jobQueue.Count; i++)
{
factory.StartNew(() => startTypeB());
}
#endregion
#region DataFeed Type C
ScheduleJobs = (Calls a static class, static method);
jobQueue = (Calls a static class, static method turn ScheduleJobs dictionary into Queue);
var factory = new TaskFactory(_TaskScheduler);
for (int i = 0; i < jobQueue.Count; i++)
{
factory.StartNew(() => startTypeC());
}
#endregion
}
}
}
if (_TaskScheduler.NumberOfRemainingScheduledTasks == 0)
{
_BlockThreadDatafeedSourceTaskScheduler.Set();
}
}
void startTypeA()
{
(In this method, it creates a object from another project class which calls a WCF Service and select data and insert into local db and run stored procedures)
}
void startTypeB()
{
(Same as startTypeA but calls a different WCF and insert into the same set of tables which startTypeA also insert into then also run a same set of stored procedures)
}
void startTypeC()
{
(Same as startTypeC but calls a different WCF and into different set of tables than startTypeA and startTypeB then run different set of stored procedures)
}
...
I was able to grab all the data from all 3 set of WCF services but the problem is after Type A and Type B insert the data and both calls the same set of stored procedures a few Job Queue had Error 1205, deadlock. Then after service has stopped, I had to manually rerun the stored procedures to process those leftover.
Can anyone know how to fix the deadlock, also I use AutoResetEvent to keep a thread blocked while another thread is processing. It doesn't seem like its doing its job.
I was thinking for alternative way but I would like to keep the same logic, task factory...
My alternative way, non-tested with actual code, but I wrote a draft similar to what I needed, but I am unsure if deadlock will still exists
class Program
{
static SemaphoreSlim _sem = new SemaphoreSlim(3);
static void Main()
{
for (int i = 1; i <= 3; i++)
{
new Thread(RunThisMethod).Start(i);
}
Console.ReadLine();
}
static void RunThisMethod(Object id)
{
Console.WriteLine(id + " wants to enter");
_sem.Wait();
if (id.ToString() == "1")
{
Console.WriteLine("Start Type A");
Thread.Sleep(3000);
Console.WriteLine("End Type A");
}
else if (id.ToString() == "2")
{
Console.WriteLine("Start Type B");
Thread.Sleep(6000);
Console.WriteLine("End Type B");
}
else if (id.ToString() == "3")
{
Console.WriteLine("Start Type C");
Thread.Sleep(9000);
Console.WriteLine("End Type C");
}
_sem.Release();
}
}