当我使用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无论我跨越多少线程,我都无法真正看到“range”值被初始化并显示为10。在这里初始化的范围变量在哪里,以及为什么在初始化静态变量时存在线程和任务的区别?
我是不是漏掉了一些基本的东西?提前谢谢。
发布于 2015-11-28 13:49:08
您的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-28 13:45:36
在第一种情况下,初始化类的线程(运行静态构造函数的线程)将range变量初始化为10。它将等于所有其他线程上的0。然后从同一个线程调用Parallel.Invoke。
Parallel.Invoke将调用当前线程上的第一个操作和线程池Task上的第二个操作,而不是生成两个线程。因为它返回所有操作后,就不需要为此使用3个线程,其中一个线程被阻塞,等待其他两个线程完成。
你可以找到参考源中的相关代码
// 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个线程,因此不会从inital线程执行任何Console.WriteLine。在这种情况下,您将永远看不到10值。
https://stackoverflow.com/questions/33971793
复制相似问题