3

当我使用 ThreadStatic 属性探索线程和任务时,我遇到了一些奇怪的事情。我相信这可能非常特定于线程和任务。考虑下面的代码片段:

[ThreadStatic]
static int range=10;


 Action action = () =>
           {Console.WriteLine("Thread = {0}, Value = {1}", Thread.CurrentThread.ManagedThreadId, range);

Parallel.Invoke( action, action);

这给出了输出:

Thread = 2, Value = 10 
Thread = 3, Value = 0

这绝对没问题,因为 ThreadStatic 变量只能初始化一次,所以第二行显示为 0。

但是,请考虑以下情况:

[ThreadStatic]
static int range=10;

new Thread(() =>
{
Console.WriteLine("Thread = {0}, Value = {1}" Thread.CurrentThread.ManagedThreadId, range);
            }).Start();

new Thread(() =>
{
Console.WriteLine("Thread = {0}, Value = {1}" Thread.CurrentThread.ManagedThreadId, range);
            }).Start();

这一行给了我输出:

Thread = 6, Value = 0
Thread = 7, Value = 0

我跨越了多少线程,我真的看不到“范围”值被初始化并显示为 10。这里初始化的范围变量在哪里以及为什么在初始化静态变量时线程和任务之间存在区别?

我在这里缺少一些基本的东西吗?提前致谢。

4

2 回答 2

3

您的 [ThreadStatic] 由包含此代码的类的静态构造函数初始化。由创建类的实例或使用静态成员的线程,以先到者为准。所以根据定义,你创建的两个线程永远看不到初始值。

古怪的行为实际上在第一个片段中。您没有指望的是 Parallel.Invoke() 还使用调用 Invoke() 的线程来完成部分工作。所以它实际上可以看到初始值。稍微重写一下代码可以告诉你:

class Test {
    [ThreadStatic]
    static int range=10;

    public static void Run() {
        Action action = () => {
            Console.WriteLine("Thread = {0}, Value = {1}", Thread.CurrentThread.ManagedThreadId, range);
        };
        Console.WriteLine("Start thread = {0}, Value = {1}", Thread.CurrentThread.ManagedThreadId, range);
        Parallel.Invoke(action, action);
    }
}

输出:

Start thread = 8, Value = 10
Thread = 8, Value = 10
Thread = 9, Value = 0

当然不是真正的问题,您不能在并行代码中使用 [ThreadStatic]。

于 2015-11-28T13:49:08.460 回答
1

在第一种情况下,range变量已由初始化10类的线程(运行静态构造函数的线程)初始化。它将等于0所有其他线程。你Parallel.Invoke从同一个线程调用。

不会产生两个线程,而是在当前Parallel.Invoke线程上调用第一个操作,然后在 threadpool 上调用第二个操作。由于它在所有操作完成后返回,因此无需为此使用 3 个线程,其中一个被阻塞等待其他 2 个完成。Task

您可以在参考源中找到相关代码

// Optimization: Use current thread to run something before we block waiting for all tasks.
tasks[0] = new Task(actionsCopy[0]);
tasks[0].RunSynchronously(parallelOptions.EffectiveTaskScheduler);

您的第二个片段产生 2 个线程,因此不会Console.WriteLine从初始线程执行。10在这种情况下,您将永远看不到价值。

于 2015-11-28T13:45:36.777 回答