1

我目前正在开发一个多线程项目。主要用于学习目的。我在这个项目中的部分是编写一个服务器应用程序。
但是我到了这样一个地步,即整个变量锁定有点令人困惑,因为我不知道它是如何工作的,以及我必须在何时/何地使用它。

可以说我有一个class ClientHandler包含一个List<Client> clientList.
ClientHandler有一个ClientList返回的属性clientList

private List<Client> clientList;
public List<Client> ClientList
{
    get { lock (lockObject) return clientList; }
    set { lock (lockObject) clientList = value; }
}

NetworkHandler运行一秒钟Thread,适用于 this List<>
在这个网络Thread中,检索到的数据在使用时List<>被另一个锁定。 我的问题是这种锁定是如何工作的。 如果我在网络中(与object

lockList<>ThreadobjectClientHandler它是线程安全的吗?所以一般来说,如果你lock是一个带有任何变量的变量object,它是否会被其他试图访问它的人锁定?
我只是想确保List<>在另一个Thread.

4

1 回答 1

3

我假设您希望 List 本身通过 Add/Remove/Clear/foreach 方法在单独的线程上传递和操作,而不是对象本身。

如果是这种情况,那么 List 本身需要对每个操作(添加、删除等)实施内部锁定机制。列表创建的是lockObject,而不是你。

显然 aList<T>无法做到这一点,因此您需要从它派生或实现自己的 IList/ICollection 类,或者您可以只使用System.Collections.Concurrent已经为此目的设计的命名空间中的集合,例如ConcurrentDictionary.

如果你想让集合中的对象可以被多个线程访问,那么你必须让这些对象线程安全......这是一个完全独立的步骤。

有关 lock 关键字如何工作的简要说明:

当您通过指定锁定对象时lock (someObject) { },代码块内的所有内容将仅在同一对象上的每个其他锁定实例未执行时才会执行。

在锁定代码块的开头,它在某处设置一个线程安全标志,上面写着“我正在保留这个对象”,而在锁定代码块的末尾,它说“我不再保留这个对象”。在锁块开始时,如果它试图锁定一个对象但该对象已经被锁定,那么它将无限期地等待,直到它可以成功获得锁,从而阻塞进程中的调用线程。

在您的示例中,您使用的是内联代码块:

get { lock (lockObject) return clientList; }

这相当于:

get
{
    lock (lockObject)
    {                       // Lock starts here
        return clientList;
    }                       // Lock ends here
}

因此,如果您访问该属性,那么一旦将对象提供给该属性的调用者,该对象就会被解锁。然后调用者可以继续调用该 List 上的 Add() 方法,并且在内部它将访问没有锁定机制的内部集合,因此它不是线程安全的。

相反,List 每次访问内部字段(例如字段)时都需要调用 lock _innerList,如下所示:

public void Add(object item)
{
    lock (_innerList)
    {
        _innerList.Add(item);
    }
}
于 2013-09-30T19:17:48.820 回答