在c#中为多线程锁定数据表的正确方法

本文关键字:方法 数据表 锁定 多线程 | 更新日期: 2023-09-27 17:50:52

这是锁定和修改由多个线程共享的DataTable的正确方法吗?如果不是,正确的做法是什么?

private void DoGeocodeLookup(object info)
{
    ParameterRow data = (ParameterRow)info;
    DataRow dr = data.Dr;
    int localIndex = data.Index;
    ManualResetEvent doneEvent = data.m_doneEvent; 
    Geocode_Google.GeoCode gc = new GeoCode();
    gc.Addr_In = m_dtAddress.Rows[localIndex]["AddressStd_tx"].ToString();
    gc.GeoCodeOne();
    if (gc.Status == "OK")
    {
        //write back to temporary datatable
        lock( m_TempTable.Rows.SyncRoot )
        {
            m_TempTable.Rows[localIndex]["GL_Address"] = gc.Thoroughfare_tx; 
        }
    }
    doneEvent.Set(); 
}

My Structure:

struct ParameterRow
{
    private DataRow m_row;
    private int m_index;
    public DataRow Dr
    {
        get { return m_row; }
        set { m_row = value; }
    }
    public int Index
    {
        get { return m_index; }
        set { m_index = value; }
    }
    public ManualResetEvent m_doneEvent;
    public ParameterRow( DataRow row, int index, ManualResetEvent doneEvent)
    {
        m_row = row;
        m_index = index;
        m_doneEvent = doneEvent; 
    }
}

启动所有线程的代码片段:

//make temporary table
m_TempTable = new DataTable();
m_TempTable = m_dtAddress.Copy();
for (int index = 0; index < m_geocodes; index++)
{
    doneEvents[index] = new ManualResetEvent(false);
    ThreadPool.QueueUserWorkItem(DoGeocodeLookup, new ParameterRow( m_dtAddress.Rows[index], index, doneEvents[index]));  
}
WaitHandle.WaitAll(doneEvents);

在c#中为多线程锁定数据表的正确方法

您的示例不需要对DataTable进行任何锁定。在DoGeocodeLookup内部,您只执行DataTable的读取。您对表执行的唯一访问是查找一行,这算作读。DataTable类被标记为对多线程读操作是安全的。如果你想在DoGeocodeLookup中添加新行,那么你需要锁。

你唯一改变的是由localIndex指定的单个DataRow中的数据。由于对DoGeocodeLookup的每次调用都使用不同的行——表中的一行只会被一个线程更新,因此不会出现同步问题。这样就不需要锁了

这个帖子非常有用,可能对你的问题有帮助。普遍的共识是使用联锁。增量(要更新的对象)。锁定是缓慢的,并且您必须记住您可能锁定了正在更新的对象的所有位置。易失性并不意味着CPU A能马上看到CPU B的变化。