Click here to Skip to main content
15,898,036 members
Articles / Database Development / SQL Server

Database Concurrency Patterns - SIP and SUP

Rate me:
Please Sign up or sign in to vote.
3.94/5 (6 votes)
29 Jul 2008CPOL4 min read 28.1K   151   26  
Take a look at two new patterns to help with database concurrency: SIP and SUP.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Threading;

namespace DatabaseConcurrency.SingleUpdatePattern
{
    public partial class Form1 : Form
    {
        private List<Thread> tList;
        private DataSet ds;
        private SynchronizationContext _uiContext;
        private bool clearRows = false;
        private int threadsComplete = 0;
        private ManualResetEvent flagUpdate = new ManualResetEvent(false);
        private Thread processingThread;

        public Form1()
        {
            InitializeComponent();
            _uiContext = WindowsFormsSynchronizationContext.Current;
        }
        /// <summary>
        /// Create a variable number of threads for processing.
        /// This will simulate concurrent database users.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button1_Click(object sender, EventArgs e)
        {
            threadsComplete = 0;
            flagUpdate.Reset();
            clearRows = false;
            ds = new DataSet();
            Dal.Setup();
            button2.Enabled = true;
            button1.Enabled = false;
            tList = new List<Thread>();
            Thread t;
            for (int i = 0; i < int.Parse(medThreadCount.Text); i++)
            {
                t = new Thread(ThreadExecute);
                t.Name = string.Format("Thread {0}", i);
                tList.Add(t);
                t.Start();
            }
            processingThread = new Thread(processingCallback);
            processingThread.Start();
        }
        /// <summary>
        /// Wait for all threads to finish processing before updating the UI
        /// </summary>
        /// <param name="context"></param>
        private void processingCallback(object context)
        {
            flagUpdate.WaitOne();
            if (!clearRows)
            {
                DataColumn dc = ds.Tables[0].Columns.Add();
                dc.ColumnName = "TableUpdateHistoryKey";
                for (int i = 1; i <= ds.Tables[0].Rows.Count; i++)
                {
                    ds.Tables[0].Rows[i - 1][dc] = i;
                }
                _uiContext.Post(new SendOrPostCallback(
                    delegate(object state)
                    {
                        dgvwResults.DataSource = ds.Tables[0];
                        dgvwDatabase.DataSource = Dal.GetDbResults();
                        dgvwActions.DataSource = Dal.GetActionResults();
                    }), null);
            }
        }
        /// <summary>
        /// Stop processing and set the waiting UI signal
        /// Reset the UI
        /// Abort all threads.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button2_Click(object sender, EventArgs e)
        {
            processingThread.Abort();
            processingThread = null;
            flagUpdate.Set();
            _uiContext.Post(new SendOrPostCallback(
                delegate(object state)
                {
                    clearRows = true;
                    dgvwResults.DataSource = null;
                    dgvwDatabase.DataSource = null;
                    dgvwActions.DataSource = null;
                }), null);
            button2.Enabled = false;
            button1.Enabled = true;
            foreach (Thread t in tList)
            {
                t.Abort();
            }
            tList.Clear();
            tList = null;
        }
        /// <summary>
        /// This is the callback that is used for Thread processing
        /// </summary>
        /// <param name="context"></param>
        private void ThreadExecute(object context)
        {
            for(int i = 0; i < int.Parse(medTestCount.Text); i++)
            {
                Random r = new Random();
                int Number = r.Next(int.Parse(medMaxClaimed.Text));
                DataTable dt = Dal.ThreadCall(Number,
                    Thread.CurrentThread.ManagedThreadId);
                _uiContext.Post(new SendOrPostCallback(
                    delegate(object state)
                    {
                        if (!clearRows)
                        {
                            dt.TableName = "Results";
                            ds.Merge(dt);
                        }
                        else
                        {
                            dgvwResults.DataSource = null;
                        }
                    }), null);

                Thread.Sleep(10);
            }
            threadsComplete++;
            if (threadsComplete == tList.Count)
                flagUpdate.Set();
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (tList != null)
            {
                foreach (Thread t in tList)
                {
                    t.Abort();
                }
                tList.Clear();
                tList = null;
            }
            ds = null;
            clearRows = true;
            flagUpdate.Set();
            if (processingThread != null)
            {
                processingThread.Abort();
            }
            processingThread = null;
        }

    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect
Australia Australia
George Zabanah has been architecting and developing solutions commercially from start to finish for over 11 years. He has been programming since he was 11 (for over 25 years now!) using many different technologies (almost all Microsoft). George is proficient in many languages and employs best practices wherever possible using design patterns, .NET, XSLT, XML, Regular Expressions, various flavours of SQL (to name just a few). His favourite tools, however, are the whiteboard and Sparx Enterprise Architect/Powerpoint. Many waking moments have been spent by George thinking about solutions in his head (even while watching tv). His best moments are the "Eureka" moments when he wakes up from a good sleep (or after watching tv) to find that his latest challenge has been solved!

Comments and Discussions