David Chen

David Chen

  • NA
  • 1
  • 2k

SQL Deadlock, Task Factory Treading Problem

Aug 22 2012 7:52 PM
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();
        }
    }