首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >线程与任务中的ThreadStatic攻击

线程与任务中的ThreadStatic攻击
EN

Stack Overflow用户
提问于 2015-11-28 13:20:46
回答 2查看 1.1K关注 0票数 3

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

代码语言:javascript
复制
[ThreadStatic]
static int range=10;


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

Parallel.Invoke( action, action);

这给出了输出:

代码语言:javascript
复制
Thread = 2, Value = 10 
Thread = 3, Value = 0

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

但是,请考虑以下情况:

代码语言:javascript
复制
[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();

这一行给出了输出:

代码语言:javascript
复制
Thread = 6, Value = 0
Thread = 7, Value = 0

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

我是不是漏掉了一些基本的东西?提前谢谢。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2015-11-28 13:49:08

您的ThreadStatic由包含此代码的类的静态构造函数初始化。通过创建类的实例或使用静态成员的线程(以第一种方式为准)。因此,根据定义,您创建的两个新线程永远看不到初始值。

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

代码语言:javascript
复制
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);
    }
}

输出:

代码语言:javascript
复制
Start thread = 8, Value = 10
Thread = 8, Value = 10
Thread = 9, Value = 0

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

票数 3
EN

Stack Overflow用户

发布于 2015-11-28 13:45:36

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

Parallel.Invoke将调用当前线程上的第一个操作和线程池Task上的第二个操作,而不是生成两个线程。因为它返回所有操作后,就不需要为此使用3个线程,其中一个线程被阻塞,等待其他两个线程完成。

你可以找到参考源中的相关代码

代码语言:javascript
复制
// 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值。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/33971793

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档