I'm using LINQ to SQL and after I submit some changes I want to spawn a thread which looks through all the changes and updates our lucene index as necessary. My code looks vaguely like:
(new Thread(() => { UpdateIndex(context.G开发者_Python百科etChangeSet()); }).Start();
Sometimes though I get an InvalidOperationException, which I think is because context.GetChangeSet() is not thread-safe, and so if the change set is modified in one thread while another thread is enumerating through it, problems arise.
Is there a "thread-safe" version of GetChangeSet()? Or some way I can do ChangeSet.clone() or something?
Instance members of the DataContext class are not thread-safe.
In order to avoid race conditions you should invoke the DataContext.GetChangeSet method from the same thread that makes the modifications tracked by the DataContext instance. For example:
public class CustomerDao : IDisposable
{
private DataContext context;
public CustomerDao()
{
this.context = new DataContext("SomeConnectionString");
}
public void Insert(Customer instance)
{
this.context.Customers.InsertOnSubmit(instance);
this.StartUpdateIndex();
this.context.SubmitChanges();
}
public void Delete(Customer instance)
{
this.context.Customers.DeleteOnSubmit(instance);
this.StartUpdateIndex();
this.context.SubmitChanges();
}
public void Dispose()
{
if (this.context != null)
{
this.context.Dispose();
}
}
private void StartUpdateIndex()
{
ChangeSet changes = this.context.GetChangeSet();
ThreadPool.QueueUserWorkItem(
state => this.UpdateIndex((ChangeSet)state), changes);
}
}
This assumes that the Insert and Delete methods are being called on a given instance of the CustomerDao class from a single thread.
I only needed to extract a small amount of data from each object, so for I ended up just extracting the text, putting it into a new object, then sending that new object off. This saved me a lot of trouble from having to deal with locking everywhere else, but I think Enrico's answer is probably the "real" one, so leaving his marked as the solution.
精彩评论