我有一个使用unthread-safe集合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();
}
我想将其转换为无锁定。要做到这一点,我在这个函数ConcurrentDictionary集合中使用而不是List集合,所以我的函数开始看起来如此:
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)?如何解决我的错误?
答案 0 :(得分:1)
如果您要更换存储列表的变量,那么它就不会同时发生。您需要使用它提供的并发方法。请参阅MSDN article。
中的示例使用TryAdd
,TryUpdate
,TryRemove
或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.
}