25

我有一个使用 HTTP 侦听器编写的 HTTP 服务器,我想以某种方式声明某些变量可以从线程中的任何位置访问。

  • 我的网络服务器类是基于实例的,所以我不能真正使用静态变量。
  • 我可以使用实例变量,因为所有代码都在一个类中,但是……我不知道。

我想过使用字典:Dictionary</*[type of Thread ID here]*/,ThreadData>,但我担心可能存在线程问题。ThreadData可能一个类实例,但我可能会使用一个结构,这取决于哪个更有效。

  • 如果我将字典键入线程 ID 并对其进行编程,以便一个线程在字典中请求它自己的条目,那么在访问字典时是否会出现任何与线程相关的问题?
  • 每个线程都会添加自己的条目。添加新线程项时是否必须锁定字典?如果是这样,我是否可以使用单独的锁定对象来允许线程同时访问自己的数据?

使用并发字典会有优势吗?还有另一种更线程安全的方法吗?

我目前正在使用ThreadPool.QueueUserWorkItem. 我不确定这是否为每个项目使用了一个新线程。如果没有,那么我也可以将其键入上下文。

更新:根据ThreadPool 类 - MSDN,它确实重用了线程。而且它不会清除线程数据。

线程池重用线程时,不会清除线程本地存储中的数据,也不会清除带有 ThreadStaticAttribute 属性标记的字段中的数据。因此,当一个方法检查线程本地存储或标记有 ThreadStaticAttribute 属性的字段时,它找到的值可能是线程池线程的早期使用遗留下来的。

4

4 回答 4

35

一种解决方案是使用具有以下属性的公共静态字段ThreadStatic

[ThreadStatic]
public static int ThreadSpecificStaticValue;

标有 ThreadStaticAttribute 的静态字段不在线程之间共享。每个执行线程都有一个单独的字段实例,并独立设置和获取该字段的值。如果在不同的线程上访问该字段,它将包含不同的值。

于 2013-03-14T16:22:14.007 回答
7

您可以使用线程类的内置存储机制:

public class Program
{
  private static LocalDataStoreSlot _Slot = Thread.AllocateNamedDataSlot("webserver.data");

  public static void Main(string[] args)
  {
    var threads = new List<Thread>();

    for (int i = 0; i < 5; i++)
    {
      var thread = new Thread(DoWork);
      threads.Add(thread);
      thread.Start(i);
    }

    foreach (var thread in threads) thread.Join();
  }

  private static void DoWork(object data)
  {
    // initially set the context of the thread
    Thread.SetData(_Slot, data);

    // somewhere else, access the context again
    Console.WriteLine("Thread ID {0}: {1}", Thread.CurrentThread.ManagedThreadId, Thread.GetData(_Slot));
  }

}

样本输出:

在此处输入图像描述

这也适用于线程池产生的线程。

于 2013-03-14T16:21:42.510 回答
0

如果您的网络服务器是基于实例的,为什么不将所有必需的数据保留在其中?如果每个实例都锁定到某个线程,应该没有问题。

于 2013-03-14T16:08:57.033 回答
-2

为什么要创建 HTTP 服务器,使用SignalR,看起来很奇怪的答案,但想想看

于 2013-03-14T16:25:30.167 回答