5

这是锁定和修改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(); 
}

我的结构:

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);
4

2 回答 2

8

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

您唯一要更改的是由DataRow指定的单个数据中的数据localIndex。由于每次调用都DoGeocodeLookup使用不同的行 - 表中的单行只会由一个线程更新,因此您不会有同步问题。所以这也不需要锁定。

于 2013-01-07T20:00:20.120 回答
0

线程信息量很大,可能对您的问题有所帮助。普遍的共识是使用 Interlock.Increment(object to be updated)。锁定很慢,您必须记住您可能已锁定正在更新的对象的所有位置。而且 volatile 并不一定意味着 CPU A 会立即看到 CPU B 刚刚更改的内容。

于 2013-01-07T19:18:50.967 回答