1

私はスレッドセーフでないコレクション List を使用する関数を持っています。スレッドセーフにするために、lock-operator を使用します。

public void ShowData(ref DataGridView dmRequests, ref DataGridView URL, ref DataGridView dmData, ref DataGridView errorCodes)
{
    List<KeyValuePair<string, ulong>> dmReqList = new List<KeyValuePair<string, ulong>>();
    List<KeyValuePair<string, ulong>> urlReqList = new List<KeyValuePair<string, ulong>>(); 
    List<KeyValuePair<string, ulong>> dmDataList = new List<KeyValuePair<string, ulong>>();
    List<KeyValuePair<string, ulong>> errCodesList = new List<KeyValuePair<string, ulong>>();

    lock (m_logStruct.domainName)
    {
        dmReqList = m_logStruct.domainName.ToList();
    }
    lock(m_logStruct.URL)
    {
        urlReqList = m_logStruct.URL.ToList();
    }
    lock(m_logStruct.domainData)
    {
        dmDataList = m_logStruct.domainData.ToList();
    }
    lock(m_logStruct.errorCodes)
    {
        errCodesList = m_logStruct.errorCodes.ToList();
    }

    dmRequests.DataSource = dmReqList.OrderBy(x => x.Key).ToList();
    URL.DataSource = urlReqList.OrderBy(x => x.Key).ToList();
    dmData.DataSource = dmDataList.OrderBy(x => x.Key).ToList();
    errorCodes.DataSource = errCodesList.OrderBy(x => x.Key).ToList();
}

ロックフリーに変換したい。それを行うために、List コレクションの代わりにこの関数 ConcurrentDictionary コレクションで使用したので、関数は次のように見え始めます。

public void ShowData(ref DataGridView dmRequests, ref DataGridView URL, ref DataGridView dmData, ref DataGridView errorCodes)
{
    try
    {
        ConcurrentDictionary<string, ulong> dmReqList = new ConcurrentDictionary<string, ulong>();
        ConcurrentDictionary<string, ulong> urlReqList = new ConcurrentDictionary<string, ulong>();
        ConcurrentDictionary<string, ulong> dmDataList = new ConcurrentDictionary<string, ulong>();
        ConcurrentDictionary<string, ulong> errCodesList = new ConcurrentDictionary<string, ulong>();

        dmReqList = m_logStruct.domainName;
        urlReqList = m_logStruct.URL;
        dmDataList = m_logStruct.domainData;
        errCodesList = m_logStruct.errorCodes;

        dmRequests.DataSource = dmReqList.OrderBy(x => x.Key);
        URL.DataSource = urlReqList.OrderBy(x => x.Key).ToList();//I get error here: Index is out of range                
        dmData.DataSource = dmDataList.OrderBy(x => x.Key).ToList();              
        errorCodes.DataSource = errCodesList.OrderBy(x => x.Key).ToList();
    }
    catch(IOException e)
    {
        MessageBox.Show(e + " Something bad has been occurred here!");
    }

}

しかし、この関数では、エラーが発生し始めます(インデックスが範囲外です)。スレッドセーフコレクション(ConcurrentDictionary)を正しく使用するには? エラーを修正するにはどうすればよいですか?

4

1 に答える 1

1

リストを格納している変数を置き換える場合、同時実行にはなりません。それが提供する並行メソッドを使用する必要があります。MSDN 記事の例を参照してください。

リストに追加したり、リストを更新したりするには、次の代わりに、、、またはをTryAdd使用TryUpdateTryRemoveます。AddOrUpdate

dmReqList = m_logStruct.domainName;

次のようにします。

foreach (var item in m_logStruct.domainName)
{
    dmReqList.TryAdd(item.Key, item.Value);
}

更新: アレクセイが指摘したように、dmReqList をローカルで定義しています。これは、他のスレッドがアクセスできないため、ConcurrentDictionary であることから何のメリットも得られないことを意味します。また、元の例から、ロックを適用したため、他のスレッドを介して m_logStruct にアクセスできることを暗示しています。含意が正しければ、それが ConcurrentDictionary である必要があります。したがって、コードは次のようになります。

private ConcurrentDictionary<string, ulong> _domainNames = new ConcurrentDictionary<string, ulong>();

public void ShowData(ref DataGridView dmRequests)
{
    dmRequests.DataSource = _domainNames.OrderBy(x => x.Key);  //Set the current values of the dictionary to the grid.
}

public void MultiThreadedMethod()
{
    _domainNames.TryAdd(someKey, someValue);  //Access the dictionary from multiple threads.
}
于 2014-10-21T14:16:29.490 に答える