|
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.
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!