views:

299

answers:

4

Suppose I'm accessing a DataTable from multiple threads. If I want to access a particular row, I suspect I need to lock that operation (I could be mistaken about this, but at least I know this way I'm safe):

// this is a strongly-typed table
OrdersRow row = null;
lock (orderTable.Rows.SyncRoot) {
    row = orderTable.FindByOrderId(myOrderId);
}

But then, if I want to update that row, should I lock the table (or rather, the table's Rows.SyncRoot object) again, or can I simply lock the row?

+4  A: 

you don't need to lock for reads - just for writes / updates. lock the smallest amount that you can, to ensure data consistency... usually just the one row that you are updating. if you are updating parent / child relationships between tables, you'll need to lock each row in each table.

Derick Bailey
The link provided by Kevin (http://social.msdn.microsoft.com/Forums/en-US/netfxbcl/thread/11b69e1a-ad6c-48d5-8e14-264af5b0692e) does seem to indicate that locking the table is necessary, actually. The MSFT rep says: "Assuming that updating a single row will not impact anything else in the table is dangerous as you are relying upon a potential implementation detail that can easily be broken at a later date." Do you have any insight as to whether or not this is true?
Dan Tao
+2  A: 

The datatable is only safe for multi threaded read operations:

http://msdn.microsoft.com/en-us/library/system.data.datatable.aspx

http://social.msdn.microsoft.com/Forums/en-US/netfxbcl/thread/11b69e1a-ad6c-48d5-8e14-264af5b0692e

On reading about the datatable there is conflicting information concerning the ability to lock the table and allow you to safely update data in a row. According to the second link you can lock the table and update the row. Being this is from a MS MVP, I would say that you probably can lock the table and be ok.

Kevin
The link says:"This type is safe for multithreaded read operations. You must synchronize any write operations"Doesn't this mean that a lock is the correct thing to do for multithreaded access?
code4life
I'm confused; the first link you provided seems to say that you only need to lock writes (though it doesn't say *what* to lock). The second seems to indicate that locking the table is the correct approach. Neither seems to agree with your statement that you cannot lock the table and expect reads to be consistent. Am I missing something?
Dan Tao
My first statement was incorrect. I found conflicting information. You don't need to lock the table to read data as that is ok. You need to lock the table to write data.
Kevin
A: 

One alternative is to wrap the dataset inside a class and make the methods that will access this dataset threadsafe. This might be a little more convienient as compared to locking rows at various different places.

Aseem Gautam
+1  A: 

Actually, just performing a lock in one place on the DataTable or DataRow doesn't actually do anything. An important aspect to remember in using Monitor locks (which is what a lock block is) is that locking an object doesn't do anything to it; that's one reason that some advocate using dedicated locking objects rather than locking the resource itself, since it forces you to realize that you have to perform the lock (and on the same object) whenever you're dealing with the resource.

That being said, it's a better idea to lock the entire DataTable, as the data storage itself is there (the DataRow objects internally only contain an offset into the DataTable as to where to retrieve the data). Because of this, even if you synchronize access to individual rows, updating two different rows simultaneously will cause you to update the same data storage mechanism in a non-synchronized manner.

There's a conflict here between viewing internal types as a "black box" and locking only what you need to (which, in this case, would lead you to a faulty conclusion of only locking the row) and trying to gain insight into the internal workings of the type and relying on implementation details that could change.

The upshot is that, right now, you should lock the entire DataTable to avoid updating the internal data storage system in a non-synchronized manner.

Adam Robinson
Very insightful answer, and I can see why you felt the need to point out how the `lock` mechanism works... I did realize locking does not do anythign *to* an object; I suppose a better way I could have worded my question would have been "Do I need to synchronize update operations per-row or per-table?" In any case, it's clear to me at this point that I must synchronize updates to *any* row across the entire table--whether by locking the table or a dedicated "table lock" (in this case, I think the `Rows.SyncRoot` object serves that purpose well, actually).
Dan Tao