pragmus
pragmus

Reputation: 4063

Using thread-safe ConcurrentDictionary collection

I've a such function which uses unthread-safe collection List, also to be thread-safe it uses 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();
}

I want to convert it to do it lock-free. To do it I've used in this function ConcurrentDictionary collection instead of List collection, so my function begin look so:

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!");
    }

}

But in this function I begin get error(Index is out of range). How to use thread-safe collection(ConcurrentDictionary) correctly? How to fix my error?

Upvotes: 1

Views: 1427

Answers (1)

Aaron Hawkins
Aaron Hawkins

Reputation: 2691

It's not going to be concurrent if you're replacing the variable where you're storing the list. You need to use the concurrent methods that it provides. See the examples in the MSDN article.

Use TryAdd, TryUpdate, TryRemove or AddOrUpdate in order to add to the list or update the list so rather than:

dmReqList = m_logStruct.domainName;

Do something like:

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

UPDATE: As pointed out by Alexei, you're defining the dmReqList locally. This means that you're getting no benefit from it being a ConcurrentDictionary because no other thread could access it anyway. Also, you imply from your original example that m_logStruct is accessible via other threads because you applied the lock to it. If the implication is correct, then that is what needs to be a ConcurrentDictionary. So, your code would need to look more like this:

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.
}

Upvotes: 1

Related Questions