|
dev
newsgroups
|
|||||||||||||||||||||||
|
|||||||||||||||||||||||
Thread safety of DataTable class - Filling on background thread OK?The DataTable documentation says: "This type is safe for multithreaded read operations. You must synchronize any write operations." So I should be able to do the following safely? Create and fill a DataTable on a worker thread and then pass that same DataTable object over to the GUI thread. Then as long as the worker thread no longer touches the DataTable, the GUI thread can read and write to it all it wants? Or the GUI thread could create the DataTable and pass it to the worker thread for filling? Or both threads could even write to the same DataTable over time, as long as they used some kind of lock to insure only one wrote at a time? I would be nice if the documentation explicitly said which methods were thread safe. That is, which involved only "read" operations and hence could be done at any time from any thread. Thanks, Alan Alan,
The text is in my idea refering in VB.Net to the Synclock procedures http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vblr7/html/vastmSyncLock.asp I hope this helps, Cor Show quote "Alan Cobb" <alan.spam.off@spam.off.alancobb.spam.off.com> schreef in bericht news:5k12a211mv70h1r5a8qj0bme8e0568vbd9@4ax.com... > Hi, > > The DataTable documentation says: > "This type is safe for multithreaded read operations. > You must synchronize any write operations." > > So I should be able to do the following safely? > Create and fill a DataTable on a worker thread and then > pass that same DataTable object over to the GUI thread. > Then as long as the worker thread no longer touches > the DataTable, the GUI thread can read and write to it > all it wants? > > Or the GUI thread could create the DataTable and pass it > to the worker thread for filling? > > Or both threads could even write to the same DataTable > over time, as long as they used some kind of lock to > insure only one wrote at a time? > > I would be nice if the documentation explicitly said which > methods were thread safe. That is, which involved only > "read" operations and hence could be done at any time > from any thread. > > Thanks, > Alan Hi Alan,
Show quote "Alan Cobb" <alan.spam.off@spam.off.alancobb.spam.off.com> wrote in message Yes.news:5k12a211mv70h1r5a8qj0bme8e0568vbd9@4ax.com... > Hi, > > The DataTable documentation says: > "This type is safe for multithreaded read operations. > You must synchronize any write operations." > > So I should be able to do the following safely? > Create and fill a DataTable on a worker thread and then > pass that same DataTable object over to the GUI thread. > Then as long as the worker thread no longer touches > the DataTable, the GUI thread can read and write to it > all it wants? > It could, as long as no fields are databound to UI controls.> Or the GUI thread could create the DataTable and pass it > to the worker thread for filling? > Yes, unless data is databound. In this case, you have to do all writtings > Or both threads could even write to the same DataTable > over time, as long as they used some kind of lock to > insure only one wrote at a time? from the thread that created UI controls. > There is only a bunch of threadsafe controls/components out there becuase of > I would be nice if the documentation explicitly said which > methods were thread safe. That is, which involved only > "read" operations and hence could be done at any time > from any thread. performance hit. You have to assume that methods are not threadsafe unless othwerise specified. And note, that read only methods are not thread safe by default. -- Miha Markic [MVP C#, INETA Country Leader for Slovenia] RightHand .NET consulting & development www.rthand.com Blog: http://cs.rthand.com/blogs/blog_with_righthand/ Thanks Cor and Miha,
Actually my current situation does not require a lot of multi-threading, but I was curious. I am now filling a DataTable asynchronously using a BackgroundWorker component. When the filling is done the DataTable gets handed back to the GUI thread and from then on the GUI thread deals with it alone. This works fine and it makes up for the lack of "built-in" asynchronous Load/Fill support in ADO.NET 2.0. Alan "Alan Cobb" <alan.spam.off@spam.off.alancobb.spam.off.com> wrote in message Sure, this a good approach. I do likewise with save (I create a copy using news:hhb6a2th6egs82kr1s2p72k40c73k3vmt3@4ax.com... > Thanks Cor and Miha, > > Actually my current situation does not require a lot of > multi-threading, but I was curious. > > I am now filling a DataTable asynchronously using a > BackgroundWorker component. When the filling is done the > DataTable gets handed back to the GUI thread and from > then on the GUI thread deals with it alone. This works fine > and it makes up for the lack of "built-in" asynchronous > Load/Fill support in ADO.NET 2.0. GetChanges() beforehand). -- Miha Markic [MVP C#, INETA Country Leader for Slovenia] RightHand .NET consulting & development www.rthand.com Blog: http://cs.rthand.com/blogs/blog_with_righthand/ A related question:
It is not clear to me how to asynchronously fill a DataTable that lives inside a DataSet. Assume a BackgroundWorker thread has asynchronously filled a DataTable (which might take 10 seconds in my case, all done without blocking the GUI thread) and then returned it to the GUI thread. One way to then get the newly filled DataTable into the DataSet is to call DataSet.Merge( DataTable ). But that takes as much time (10 seconds) as the initial Fill, and it blocks the GUI thread the whole time, so the initial asynchronous Fill has not achieved "non-blocking-ness". Another possibility is to pass the BackgroundWorker thread a reference to the member DataTable inside the DataSet and have the background thread fill it directly. But if controls are bound to the DataSet, that isn't allowed, as you have said. I guess there is no way to temporarily unbind the DataSet and just assign a new filled DataTable to the internal DataTable member of the DataSet, rather than Merging it in? Any suggestions? Thanks, Alan "Alan Cobb" <alan.spam.off@spam.off.alancobb.spam.off.com> wrote in message It sounds weird. It shouldn't take that much time. Are you sure? How many news:ch49a29nl8304llefba2db17sbl0pjkq8r@4ax.com... >A related question: > > It is not clear to me how to asynchronously fill a DataTable > that lives inside a DataSet. > > Assume a BackgroundWorker thread has asynchronously filled > a DataTable (which might take 10 seconds in my case, all done > without blocking the GUI thread) and then returned it to the > GUI thread. One way to then get the newly filled DataTable into > the DataSet is to call DataSet.Merge( DataTable ). But that takes > as much time (10 seconds) as the initial Fill, records we are talking about? and it blocks the GUI > thread the whole time, so the initial asynchronous Fill has not One way is to unbind the controls before filling the data. But I would > achieved "non-blocking-ness". > > Another possibility is to pass the BackgroundWorker thread a > reference to the member DataTable inside the DataSet and have > the background thread fill it directly. But if controls are bound > to the DataSet, that isn't allowed, as you have said. I guess > there is no way to temporarily unbind the DataSet and just > assign a new filled DataTable to the internal DataTable member > of the DataSet, rather than Merging it in? really rather use the Merge way. -- Miha Markic [MVP C#, INETA Country Leader for Slovenia] RightHand .NET consulting & development www.rthand.com Blog: http://cs.rthand.com/blogs/blog_with_righthand/
Show quote
> About 150,000 records. The private bytes used by my app go up >"Alan Cobb" <alan.spam.off@spam.off.alancobb.spam.off.com> wrote in message >news:ch49a29nl8304llefba2db17sbl0pjkq8r@4ax.com... >>A related question: >> >> It is not clear to me how to asynchronously fill a DataTable >> that lives inside a DataSet. >> >> Assume a BackgroundWorker thread has asynchronously filled >> a DataTable (which might take 10 seconds in my case, all done >> without blocking the GUI thread) and then returned it to the >> GUI thread. One way to then get the newly filled DataTable into >> the DataSet is to call DataSet.Merge( DataTable ). But that takes >> as much time (10 seconds) as the initial Fill, > >It sounds weird. It shouldn't take that much time. Are you sure? How many >records we are talking about? about 100 MB because of the Fill. Is a >10 (actually more like 15) second Fill reasonable for that many records? Maybe in-memory DataTables and DataSets aren't normally used with that many records? Show quote > I noticed the method BindingSource . SuspendBinding. Is that ever > and it blocks the GUI >> thread the whole time, so the initial asynchronous Fill has not >> achieved "non-blocking-ness". >> >> Another possibility is to pass the BackgroundWorker thread a >> reference to the member DataTable inside the DataSet and have >> the background thread fill it directly. But if controls are bound >> to the DataSet, that isn't allowed, as you have said. I guess >> there is no way to temporarily unbind the DataSet and just >> assign a new filled DataTable to the internal DataTable member >> of the DataSet, rather than Merging it in? > >One way is to unbind the controls before filling the data. But I would >really rather use the Merge way. used for that purpose? Or when you say "unbind the controls" that would be something like temporarily setting BindingSource . DataSource to null or typeof( MyDataSetType ) or something like that? Thanks, Alan >>It sounds weird. It shouldn't take that much time. Are you sure? How many That's huge.>>records we are talking about? > > About 150,000 records. The private bytes used by my app go up > about 100 MB because of the Fill. Is a >10 (actually more like 15) > second Fill reasonable for that many records? > > Maybe in-memory DataTables and DataSets aren't normally used > with that many records? The real question is the design of your application. Do you really need that much records at client side? Can be done differently? > I noticed the method BindingSource . SuspendBinding. Is that ever I guessed so, but a while ago I tested and I recall that it wasn't working > used for that purpose? as expected. Not 100% sure on this, I guess I have to test a bit more. Or when you say "unbind the controls" that > would be something like temporarily setting Yes, that's why I meant - disconnecting datasource - that will always work.> BindingSource . DataSource to null or typeof( MyDataSetType ) > or something like that? -- Miha Markic [MVP C#, INETA Country Leader for Slovenia] RightHand .NET consulting & development www.rthand.com Blog: http://cs.rthand.com/blogs/blog_with_righthand/ >>>It sounds weird. It shouldn't take that much time. Are you sure? How many Yes it probably can and should be done differently.>>>records we are talking about? >> >> About 150,000 records. The private bytes used by my app go up >> about 100 MB because of the Fill. Is a >10 (actually more like 15) >> second Fill reasonable for that many records? >> >> Maybe in-memory DataTables and DataSets aren't normally used >> with that many records? > >That's huge. >The real question is the design of your application. Do you really need that >much records at client side? Can be done differently? One advantage of pulling it all into memory is that once it's there it's fast to iterate over all the records to compute some statistics, but there are probably other ways I can do that like queries. I also currently bind all 150,000 records to a grid, which apparently is a somewhat naive design. That bind to the grid also takes an additional 15 seconds, during which the GUI thread is again blocked and unresponsive. Apparently there is also no way to do the bind asynchronously and no simple stock way to get some kind of automatic paging of individual screenfuls of rows. I guess the "solution" is to just load and bind less. It has been said before: SQL's SELECT statement has a WHERE clause for a reason :). Show quote > BTW: When I tried "unbinding" the controls by setting>> I noticed the method BindingSource . SuspendBinding. Is that ever >> used for that purpose? > >I guessed so, but a while ago I tested and I recall that it wasn't working >as expected. >Not 100% sure on this, I guess I have to test a bit more. > > Or when you say "unbind the controls" that >> would be something like temporarily setting >> BindingSource . DataSource to null or typeof( MyDataSetType ) >> or something like that? > >Yes, that's why I meant - disconnecting datasource - that will always work. BindingSource.DataSource to null or typeof( MyDataSetType ) I got "Cannot bind to the property or column..." exceptions. What did work was to set DataSource to point at an empty instance of my typed DataSet. Thanks, Alan |
|||||||||||||||||||||||