dataset and locks

G

Guest

Hi Guys
I have three datatables, which are related as described below
I have not put any constraints on the table, the are never written to
a datbase, the problem I am having is updating them programaticcally, the user ca
never update them. I lock the dataset, and iterate through the three tables, updating the fields, but not the
fields involved in relations, and I seem to be running into a deadlock situation. Is there something pbviousl
wrong with what I am doing
Thanks

data = new DataTable("TraderData")
DataColumn tid = new DataColumn("TraderId", typeof(string));
DataColumn prod = new DataColumn("Product", typeof(string));
DataColumn contract = new DataColumn("Contract", typeof(string))
DataColumn netPosition = new DataColumn("NetPosition", typeof(int));
DataColumn netPositionFly = new DataColumn("NetPositionFly", typeof(int)) ;


netData = new DataTable("NetTraderData")
DataColumn name = new DataColumn("Name", typeof(string))
DataColumn net = new DataColumn("Net", typeof(double))
DataColumn dayLimit = new DataColumn("DayLimit", typeof(double));
DataColumn dayFlag = new DataColumn("DayFlag", typeof(string)) ;
DataColumn nightLimit = new DataColumn("NightLimit", typeof(double));
DataColumn nightFlag = new DataColumn("NightFlag", typeof(string));
DataColumn traderId = new DataColumn("TraderId", typeof(string));
DataColumn netprod = new DataColumn("Product", typeof(string));


productTable = new DataTable("TraderProductTable")
DataColumn idcol = new DataColumn("id", typeof(string));
DataColumn prod = new DataColumn("Prod", typeof(string));
DataColumn limit = new DataColumn("Limit", typeof(string));
productTable.Columns.Add(idcol)
productTable.Columns.Add(prod)
productTable.Columns.Add(limit)


//data = new DataTable("TraderData"); = instruments.TableNam
//productTable = new DataTable("TraderProductTable"); = trprod.TableNam
//netData = new DataTable("NetTraderData"); = nets.TableNam

DataColumn[] parentCols = new DataColumn[2]
parentCols[0] = this.ds.Tables[trprod.TableName].Columns["id"]
parentCols[1] = this.ds.Tables[trprod.TableName].Columns["Prod"]

DataColumn[] pCols = new DataColumn[2]
pCols[0] = this.ds.Tables[trprod.TableName].Columns["id"]
pCols[1] = this.ds.Tables[trprod.TableName].Columns["Prod"]

DataColumn[] childCols = new DataColumn[2]
childCols[0] = this.ds.Tables[nets.TableName].Columns["TraderId"]
childCols[1] = this.ds.Tables[nets.TableName].Columns["Product"]

DataColumn[] netChildCols = new DataColumn[2]
netChildCols[0] = this.ds.Tables[instruments.TableName].Columns["TraderId"]
netChildCols[1] = this.ds.Tables[instruments.TableName].Columns["Product"]

this.ds.Relations.Add("Net Positions", pCols , netChildCols)
this.ds.Relations.Add("Net Limits", parentCols , childCols)

update metho
lock ds
for (int k = 0 ; k < count ; k++

string product = (string)ds.Tables[1].Rows[k]["Product"]
string trader = (string)ds.Tables[1].Rows[k]["TraderId"]
string contract = (string)ds.Tables[1].Rows[k]["Contract"];

ds.Tables[1].Rows[k]["NetPosition"] = (int)current[j,2]
ds.Tables[1].Rows[k]["NetPositionFly"]= (int)current[j,3]


onwards through the three tables
 
J

Jon Skeet [C# MVP]

kk said:
I have three datatables, which are related as described below. I have
not put any constraints on the table, the are never written to a
datbase, the problem I am having is updating them programaticcally,
the user can never update them. I lock the dataset, and iterate
through the three tables, updating the fields, but not the fields
involved in relations, and I seem to be running into a deadlock
situation. Is there something pbviously

Could you post a short but complete program which demonstrates the
problem?

See http://www.pobox.com/~skeet/csharp/complete.html for details of
what I mean by that.
 
J

Jon Skeet [C# MVP]

kk said:
Heres a cut down version of what I'm trying to do.

Thanks. I suspect it's still longer than it needs to be, but it's
definitely better than before :)
The user will not be allowed to update the dataset, it will all be
done programtically and the timer event indicates when to do this. I
have included the threading mechanismm used as well as the locking
stratergy.

The aim is to have the calcukateNetFly to run on a seperate thead
from the main UI thread. But to only have one thread running through
the method at any one time. I have not used the synchrnize attribute
on this method as I dont want to lock the whole this object, which is
what I understand the attribute to do.

Well, it basically does a lock on "this", yes. I would avoid using the
attribute.
Once this method has run I need to run the updateMainNets method, but
I need to jump back to the main UI threa, therefore am uising the
invoke method to start of with.

I'm not sure why you're running calculateNetFly on yet *another*
separate thread though. cacheTimer_Tick is already running on a non-UI
thread - why do you want to create yet another one to run
calculateNetFly?
The problem is there is a dead lock ocouring

There isn't, actually, as far as I can see. The reason calculateNetFly
is only being executed once is that you're setting updatingForm to
true, and never resetting it to false, as I've pointed out before.

You have other problems though:

o You're assigning to m_EndInvoke (you should really work out which
coding conventions you're going to use and be consistent, btw), but
never actually using the value

o I see no reason to have an AsyncCallback for MethodBeginInvoke - why
not just call updateMainNets at the end of calculateNetFly?
 
G

Guest

Well, I've written a class that replicates the locks and the threads I am using in my application. Apologies its longer than before, but on the upside is all self contained.

I've removed the m_EndInvoke and AsyncCallBack as per your suggestion, but still the update method dosent get called after a several iterations. I've put in a second timer to simulate the work with the api.

Thanks so much in advance! This is prooving very helpful.


using System;
using System.Data;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Diagnostics;
using System.Timers;

using System.Threading;
using System.Runtime.CompilerServices;


namespace WindowsApplication5
{
public class Form1 : System.Windows.Forms.Form
{
private System.IAsyncResult m_EndInvoke = null;

private delegate void createCalclulations();
private delegate void doCalclulations();

private bool updatingForm = false;
private ArrayList tempCache = new ArrayList();


private DataTable trprod ;
private DataTable nets ;
private DataTable instruments ;
private DataSet ds;
private DataGrid positions;
private Traders traders;
private TraderProducts traderproducts;
private System.Timers.Timer cacheTimer;
private System.Timers.Timer cacheTimer2;

private Object testLock = new object();

private Object boolLock = new object();

private Object calcLock = new object();

private Object updateLock = new object();

private Object updateDataset = new Object();

private object[] allCurrentNets;

private object[] allTPs ;

private System.ComponentModel.Container components = null;

private int ccc = 0;
public Form1()
{
Thread.CurrentThread.Name = "mainUIThread";
Thread.CurrentThread.Priority = ThreadPriority.Highest;
traders = new Traders();
InitializeComponent();
traderproducts = new TraderProducts();
frmDrawComponents();
loadData();

allCurrentNets = new object[10 ];

allTPs = new object[10 ];
createTimer() ;
}

private void createTimer()
{

cacheTimer = new System.Timers.Timer();
cacheTimer.Elapsed += new ElapsedEventHandler(cacheTimer_Tick );
cacheTimer.Interval = 1000;
cacheTimer.Enabled = true;

cacheTimer2 = new System.Timers.Timer();
cacheTimer2.Elapsed += new ElapsedEventHandler(cacheTimer_Tick2 );
cacheTimer2.Interval = 1000;
cacheTimer2.Enabled = true;
}


public void cacheTimer_Tick(Object source, ElapsedEventArgs e )
{
Console.WriteLine("in timer");
lock(testLock)
{
Thread.CurrentThread.Priority = ThreadPriority.Lowest;

Console.WriteLine("in test lock");
if (!this.updatingForm)
{
Console.WriteLine("in updating form");
lock(this.boolLock)
{// need to lock this to update forn variable

Console.WriteLine("in bool lock");
this.updatingForm = true;
}
this.calculateNetFly();
// method should be called from a threadpool thread
//ThreadStart theadstart = new ThreadStart(this.calculateNetFly);
//m_EndInvoke = theadstart.BeginInvoke( new AsyncCallback(MethodBeginInvoke), null);

}
}
}
public void cacheTimer_Tick2(Object source, ElapsedEventArgs e )
{
lock(this.tempCache)
{
this.tempCache.Add(null);
Console.WriteLine("peek");
}
}

// private void MethodBeginInvoke (System.IAsyncResult ar )
// {
// Console.WriteLine("method begininvoke" + Thread.CurrentThread.Name);
// updateMainNets();
//
// }
public void calculateNetFly()
{
Console.WriteLine("Current thread name from constructor: " + Thread.CurrentThread.Name);
lock(calcLock) //locking an object flag - should ensure only one thread ever comes into this method at a time
{
lock(this.tempCache)
{
int size = this.tempCache.Count;
for (int a = 0; a < size; a++ )
{
this.tempCache.RemoveAt(a);
}
}

lock(allTPs)
{
Thread.Sleep(500);
}

lock(allCurrentNets)
{
Thread.Sleep(500);
}
//Thread.Sleep(500);
}
updateMainNets();

}

private void updateMainNets()
{
Console.WriteLine("update main nets: " + System.DateTime.Now);
if (Monitor.TryEnter(updateDataset,10))
{
if (this.InvokeRequired)
{
createCalclulations cc = new createCalclulations(this.updateMainNets);
Monitor.Exit(updateDataset);
this.Invoke(cc); //marshelled to main UI thread

return;
}
Console.WriteLine("in update lock");

int count = this.ds.Tables[1].Rows.Count;

lock(allTPs)
{

for (int k = 0 ; k < count ; k++ )
{
string product = (string)ds.Tables[1].Rows[k]["Product"];
string trader = (string)ds.Tables[1].Rows[k]["TraderId"];
string contract = (string)ds.Tables[1].Rows[k]["Contract"];
ds.Tables[1].Rows[k]["NetPosition"] = ccc;
ds.Tables[1].Rows[k]["NetPositionFly"]= ccc;
}
}

int count2 = this.ds.Tables[2].Rows.Count;

lock(allCurrentNets)
{
for (int k = 0 ; k < count2 ; k++ )
{
ds.Tables[2].Rows[k]["NightLimit"] = ccc;
ds.Tables[2].Rows[k]["DayLimit"]= ccc;
}
}

int count3 = this.ds.Tables[0].Rows.Count;

for (int k = 0 ; k < count3 ; k++ )
{
ds.Tables[0].Rows[k]["Limit"] = ccc;

}
Console.WriteLine(System.DateTime.Now + " " + ccc);
ccc++;
lock(boolLock)// need to lock this to update forn variable
{
this.updatingForm= false;
Console.WriteLine("this.updatingForm " + this.updatingForm);
}
Monitor.Exit(updateDataset);
}
Application.DoEvents();
}

public void loadData()
{

object[] t00 = {"aa", "L", "ok"};
this.traders.productTable.LoadDataRow(t00,true );

object[] t01 = {"bb", "L", "ok"};
this.traders.productTable.LoadDataRow(t01,true );

object[] t02 = {"cc", "L", "ok"};
this.traders.productTable.LoadDataRow(t02,true );

object[] t03 = {"dd", "L", "ok"};
this.traders.productTable.LoadDataRow(t03,true );

object[] t04 = {"ee", "L", "ok"};
this.traders.productTable.LoadDataRow(t04,true );


object[] row = {"aa", "L", "12",0,10,"ok",20,"ok" };
this.traderproducts.netData.LoadDataRow(row,true );

object[] row1 = {"bb", "L", "12",0,10,"ok",20,"ok" };
this.traderproducts.netData.LoadDataRow(row1,true );
object[] row2 = {"cc", "L", "12",0,10,"ok",20,"ok" };
this.traderproducts.netData.LoadDataRow(row2,true );
object[] row3 = {"dd", "L", "12",0,10,"ok",20,"ok" };
this.traderproducts.netData.LoadDataRow(row3,true );
object[] row4 = {"ee", "L", "12",0,10,"ok",20,"ok" };
this.traderproducts.netData.LoadDataRow(row4,true );



object[] row6 = {"aa", "L", "JUN", 0, 0};
this.traderproducts.data.LoadDataRow(row6,true );

object[] row7 = {"bb", "L", "JUN", 0, 0};
this.traderproducts.data.LoadDataRow(row7,true );

object[] row8 = {"cc", "L", "JUN", 0, 0};
this.traderproducts.data.LoadDataRow(row8,true );

object[] row9 = {"dd", "L", "JUN", 0, 0};
this.traderproducts.data.LoadDataRow(row9,true );

object[] row10 = {"ee", "L", "JUN", 0, 0};
this.traderproducts.data.LoadDataRow(row10,true );

}
public void frmDrawComponents()
{
this.ds = new DataSet();
trprod = this.traders.productTable;
nets = this.traderproducts.netData;
instruments = this.traderproducts.data;
this.ds.Tables.Add(trprod);
this.ds.Tables.Add(instruments);
this.ds.Tables.Add(nets);

DataColumn[] parentCols = new DataColumn[2] ;
parentCols[0] = this.ds.Tables[trprod.TableName].Columns["id"];
parentCols[1] = this.ds.Tables[trprod.TableName].Columns["Prod"];

DataColumn[] pCols = new DataColumn[2] ;
pCols[0] = this.ds.Tables[trprod.TableName].Columns["id"];
pCols[1] = this.ds.Tables[trprod.TableName].Columns["Prod"];

DataColumn[] childCols = new DataColumn[2] ;
childCols[0] = this.ds.Tables[nets.TableName].Columns["TraderId"];
childCols[1] = this.ds.Tables[nets.TableName].Columns["Product"];

DataColumn[] netChildCols = new DataColumn[2] ;
netChildCols[0] = this.ds.Tables[instruments.TableName].Columns["TraderId"];
netChildCols[1] = this.ds.Tables[instruments.TableName].Columns["Product"];

this.ds.Relations.Add("Net Positions", pCols , netChildCols);
this.ds.Relations.Add("Net Limits", parentCols , childCols);


this.positions= new System.Windows.Forms.DataGrid();
this.positions.SetDataBinding(this.ds,trprod.TableName);




this.positions.BackColor = Color.Silver;
this.positions.BackgroundColor = Color.Silver;
this.positions.AllowDrop = false;
this.positions.AlternatingBackColor = System.Drawing.Color.LightGray;
this.positions.BorderStyle = System.Windows.Forms.BorderStyle.None;
this.positions.CaptionVisible = true;
this.positions.CaptionBackColor =Color.Silver;
this.positions.CaptionForeColor =Color.Red;

this.positions.FlatMode = true;
this.positions.Font = new System.Drawing.Font("Verdana", 8F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(0)));
this.positions.GridLineColor = System.Drawing.SystemColors.HighlightText;
this.positions.GridLineStyle = System.Windows.Forms.DataGridLineStyle.None;
this.positions.HeaderForeColor = Color.Red;
this.positions.PreferredRowHeight = 25;
//this.positions.ReadOnly = true;
this.positions.RowHeadersVisible = false;
this.positions.HeaderBackColor = Color.Orange;
this.positions.AllowSorting = false;
this.positions.CausesValidation = false;

this.positions.Size = new System.Drawing.Size(390,300);
this.positions.Location = new System.Drawing.Point(10 , 40);


DataGridTableStyle trstyle = new DataGridTableStyle();
trstyle.HeaderBackColor = Color.Silver;
trstyle.MappingName = trprod.TableName;

DataGridColumnStyle trid = new DataGridTextBoxColumn ();
trid.MappingName = "id";
trid.HeaderText = "ID";
trid.Width = 40;
trstyle.GridColumnStyles.Add(trid);

DataGridColumnStyle tridp = new DataGridTextBoxColumn ();
tridp.MappingName = "Prod";
tridp.HeaderText = "Prod";
tridp.Width = 40;
trstyle.GridColumnStyles.Add(tridp);

DataGridColumnStyle tridpl = new DataGridTextBoxColumn ();
tridpl.MappingName = "Limit";
tridpl.HeaderText = "lim";
tridpl.Width = 40;
trstyle.GridColumnStyles.Add(tridpl);

this.positions.TableStyles.Add(trstyle);


DataGridTableStyle ts1 = new DataGridTableStyle();
ts1.HeaderBackColor = Color.Silver;
ts1.MappingName = instruments.TableName;

DataGridColumnStyle TextCol = new DataGridTextBoxColumn();
TextCol.MappingName = "Contract";
TextCol.HeaderText = "c";
TextCol.Width = 50;
ts1.GridColumnStyles.Add(TextCol);

DataGridColumnStyle TextCol2 = new DataGridTextBoxColumn();
TextCol2.MappingName = "NetPosition";
TextCol2.HeaderText = "Net";
TextCol2.Width = 40;
ts1.GridColumnStyles.Add(TextCol2);

DataGridColumnStyle TextCol3 = new DataGridTextBoxColumn();
TextCol2.MappingName = "NetPositionFly";
TextCol2.HeaderText = "Fly";
TextCol2.Width = 40;
ts1.GridColumnStyles.Add(TextCol3);

positions.TableStyles.Add(ts1);

DataGridTableStyle netts1 = new DataGridTableStyle();
netts1.HeaderBackColor = Color.Silver;
netts1.MappingName = nets.TableName;
DataGridColumnStyle TextCol7 = new DataGridTextBoxColumn();

TextCol7.MappingName = "Name";
TextCol7.HeaderText = "";
TextCol7.Width = 20;
netts1.GridColumnStyles.Add(TextCol7);

DataGridColumnStyle TextCol8 = new DataGridTextBoxColumn();
TextCol8.MappingName = "Net";
TextCol8.HeaderText = "Net";
TextCol8.Width = 40;
netts1.GridColumnStyles.Add(TextCol8);

DataGridColumnStyle TextCol9 = new DataGridTextBoxColumn ();
TextCol9.MappingName = "DayLimit";
TextCol9.HeaderText = "Day";
TextCol9.Width = 40;
netts1.GridColumnStyles.Add(TextCol9);


DataGridColumnStyle TextCol4 = new DataGridTextBoxColumn ();
TextCol4.MappingName = "DayFlag";
TextCol4.HeaderText = "Flag";
TextCol4.Width = 40;
netts1.GridColumnStyles.Add(TextCol4);

DataGridColumnStyle TextCol5 = new DataGridTextBoxColumn ();
TextCol5.MappingName = "NightLimit";
TextCol5.HeaderText = "Night";
TextCol5.Width = 40;
netts1.GridColumnStyles.Add(TextCol5);

DataGridColumnStyle TextCol6 = new DataGridTextBoxColumn ();
TextCol6.MappingName = "NightFlag";
TextCol6.HeaderText = "Flag";
TextCol6.Width = 40;
netts1.GridColumnStyles.Add(TextCol6);

this.positions.TableStyles.Add(netts1);

this.Controls.Add(positions);


}

/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}

#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.Size = new System.Drawing.Size(300,300);
this.Text = "Form1";
}
#endregion

/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.Run(new Form1());
}
}

public class TraderProducts
{
public DataTable data;
public DataTable netData;


public TraderProducts()
{
data = new DataTable("TraderData");
DataColumn tid = new DataColumn("TraderId", typeof(string));
DataColumn prod = new DataColumn("Product", typeof(string));
DataColumn contract = new DataColumn("Contract", typeof(string));
DataColumn netPosition = new DataColumn("NetPosition", typeof(int));
DataColumn netPositionFly = new DataColumn("NetPositionFly", typeof(int)) ;

data.Columns.Add(tid);
data.Columns.Add(prod);
data.Columns.Add(contract);
data.Columns.Add(netPosition);
data.Columns.Add(netPositionFly);


netData = new DataTable("NetTraderData");
DataColumn name = new DataColumn("Name", typeof(string));
DataColumn net = new DataColumn("Net", typeof(double));
DataColumn dayLimit = new DataColumn("DayLimit", typeof(double));
DataColumn dayFlag = new DataColumn("DayFlag", typeof(string)) ;
DataColumn nightLimit = new DataColumn("NightLimit", typeof(double));
DataColumn nightFlag = new DataColumn("NightFlag", typeof(string));
DataColumn traderId = new DataColumn("TraderId", typeof(string));
DataColumn netprod = new DataColumn("Product", typeof(string));


netData.Columns.Add(traderId);
netData.Columns.Add(netprod);
netData.Columns.Add(name);
netData.Columns.Add(net);
netData.Columns.Add(dayLimit);
netData.Columns.Add(dayFlag);
netData.Columns.Add(nightLimit);
netData.Columns.Add(nightFlag);

}
}

public class Traders
{
public DataTable productTable;

private int count = 0;

public Traders()
{
productTable = new DataTable("TraderProductTable");
DataColumn idcol = new DataColumn("id", typeof(string));
DataColumn prod = new DataColumn("Prod", typeof(string));
DataColumn limit = new DataColumn("Limit", typeof(string));
productTable.Columns.Add(idcol);
productTable.Columns.Add(prod);
productTable.Columns.Add(limit);
}
}


}
 
J

Jon Skeet [C# MVP]

kk said:
Well, I've written a class that replicates the locks and the threads
I am using in my application. Apologies its longer than before, but
on the upside is all self contained.

I've removed the m_EndInvoke and AsyncCallBack as per your
suggestion, but still the update method dosent get called after a
several iterations. I've put in a second timer to simulate the work
with the api.

Well, you're now accessing updatingForm outside the lock which is
supposed to guard it, but that's not the main problem.

Your updateMainNets method is broken - you're only setting updatingForm
to false if you manage to enter the lock.

You're also still calling Application.DoEvents for no good reason.

Probably your biggest problem, however, is nothing to do with threading
- it's this code:

int size = this.tempCache.Count;
for (int a = 0; a < size; a++ )
{
this.tempCache.RemoveAt(a);
}

That will fall over with an exception if the size of tempCache is > 1.
You'll end up clearing the first half of the list, but then not the
second half because by the time you *get* to the second half, there'll
only be the first half left and you'll be trying to remove non-existent
entries.

The whole block can be replaced with:

tempCache.Clear();


The fact that this simple bug took so long to find should be a warning
to you though - you're making things much more complicated than they
should be. You're using umpteen different locks, and there may well
still be deadlock possibilities - it's too complicated to work out what
order locks are acquired in.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top