C#ThreadStatic +挥发性成员未按预期 [英] C# ThreadStatic + volatile members not working as expected

查看:176
本文介绍了C#ThreadStatic +挥发性成员未按预期的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是通过技巧和窍门看完后,我想我倒是尝试一些C#的东西,我从来没有做过的事情。因此,下面的代码提供没有实际用途,但仅仅是一个'测试功能',看看会发生什么。



无论如何,我有两个静态私有字段:

 私有静态挥发字符串staticVolatileTestString =; 
[ThreadStatic]
私有静态诠释threadInt = 0;



正如你所看到的,我测试的 ThreadStaticAttribute 挥发性关键字



不过,我有一个测试方法,看起来像这样:

 私有静态字符串TestThreadStatic(){
//首先我创建10个线程(DEFAULT_TEST_SIZE为10),并与匿名方法
名单,下起他们全部;主题> startedThreads =新的List<螺纹>();
的for(int i = 0; I< DEFAULT_TEST_SIZE ++ I){
线程t =新主题(委托(对象o){
//的匿名方法可设置为newValue为threadInt并打印新值波动测试字符串,然后1到10秒等待,然后再次将打印threadInt的挥发测试字符串值,以确认没有其他线程已经改变了它
INT的newval = randomNumberGenerator。其次(10,100);
staticVolatileTestString + = Environment.NewLine +\tthread+((INT)O)+设置threadInt为+的newval;
threadInt =的newval;
Thread.sleep代码(randomNumberGenerator.Next(1000,10000));
staticVolatileTestString + = Environment.NewLine +\tthread+((INT)O)+说完:+ threadInt;
});
t.Start(ⅰ);
startedThreads.Add(T);
}

的foreach(螺纹日在startedThreads)th.Join();

返回staticVolatileTestString;
}



我希望看到从该函数返回的是一个像这样的输出

 线程0设置threadInt至88 
线1设置threadInt至97
线2设置threadInt到11
线3设置threadInt至84
线4设置threadInt至67
线5设置threadInt至46
线6设置threadInt至94
线7设置threadInt到60
线8设置threadInt至11
线9设置threadInt至81
线5完成:46
线程2完成:11
线4完成:67
线3完成:84
线9完成:81
线6完成:94
线7完成:60
线程1完成:97
线8完成:11
线程0完成:88

不过,我得到是这样的:

 线程0设置threadInt至88 
线4设置threadInt至67
线6设置threadInt 94
线7设置threadInt至60
线8设置threadInt至11
线9设置threadInt至81
线5完成:46
线程2完成:11
线4完成:67
线3完成:84
线9完成:81
线6完成:94
线7完成:60
线程1完成:97
线8完成:11
线程0完成:88



第二个半壁江山的输出为预期(我猜想意味着ThreadStatic领域的工作就像我想),但它似乎是一个少数初期输出功率已经从第一'一半''跳过'。



<击>此外,在第一个半壁江山的主题是无序的,但我明白,一个线程不立即只要你调用运行开始();而是内部控制的操作系统将启动线程,因为它认为合适
编辑:不,他们不是,其实,我只是以为他们是因为我的大脑错过了连续编号






所以,我的问题是:什么地方出了错导致我失去对输出的第一半壁江山的几行?例如,如果是线'的螺纹3设置threadInt至84 的'?


解决方案

线程是在同一时间执行。什么概念发生是这样的:

  staticVolatileTestString + = Environment.NewLine +\tthread+((INT)O)+ 设置threadInt为+的newval; 




  1. 线程1读取staticVolatileTestString

  2. 发2读取staticVolatileTestString

  3. 发3读取staticVolatileTestString

  4. 发1追加的东西,写staticVolatileTestString回

  5. 发2追加的东西,写staticVolatileTestString回

  6. 发3追加的东西,写staticVolatileTestString回



这会导致丢失你的线条。挥发性这里没有帮助;串联字符串的整个过程不是原子。您需要使用锁围绕这些操作:

 私有静态对象同步=新的对象(); 

锁(同步){
staticVolatileTestString + = Environment.NewLine +\tthread+((INT)O)+设置threadInt为+的newval;
}


I was reading through the tips and tricks post and I thought I'd try out some of the C# stuff that I'd never done before. Therefore, the following code serves no actual purpose, but is just a 'test function' to see what happens.

Anyway, I have two static private fields:

private static volatile string staticVolatileTestString = "";
[ThreadStatic]
private static int threadInt = 0;

As you can see, I'm testing ThreadStaticAttribute and the volatile keyword.

Anyway, I have a test method that looks like this:

private static string TestThreadStatic() {
    // Firstly I'm creating 10 threads (DEFAULT_TEST_SIZE is 10) and starting them all with an anonymous method
    List<Thread> startedThreads = new List<Thread>();
    for (int i = 0; i < DEFAULT_TEST_SIZE; ++i) {
        Thread t = new Thread(delegate(object o) {
            // The anon method sets a newValue for threadInt and prints the new value to the volatile test string, then waits between 1 and 10 seconds, then prints the value for threadInt to the volatile test string again to confirm that no other thread has changed it
            int newVal = randomNumberGenerator.Next(10, 100);
            staticVolatileTestString += Environment.NewLine + "\tthread " + ((int) o) + " setting threadInt to " + newVal;
            threadInt = newVal;
            Thread.Sleep(randomNumberGenerator.Next(1000, 10000));
            staticVolatileTestString += Environment.NewLine + "\tthread " + ((int) o) + " finished: " + threadInt;
        });
        t.Start(i);
        startedThreads.Add(t);
    }

    foreach (Thread th in startedThreads) th.Join();

    return staticVolatileTestString;
}

What I'd expect to see returned from this function is an output like this:

thread 0 setting threadInt to 88
thread 1 setting threadInt to 97
thread 2 setting threadInt to 11
thread 3 setting threadInt to 84
thread 4 setting threadInt to 67
thread 5 setting threadInt to 46
thread 6 setting threadInt to 94
thread 7 setting threadInt to 60
thread 8 setting threadInt to 11
thread 9 setting threadInt to 81
thread 5 finished: 46
thread 2 finished: 11
thread 4 finished: 67
thread 3 finished: 84
thread 9 finished: 81
thread 6 finished: 94
thread 7 finished: 60
thread 1 finished: 97
thread 8 finished: 11
thread 0 finished: 88

However, what I'm getting is this:

thread 0 setting threadInt to 88
thread 4 setting threadInt to 67
thread 6 setting threadInt to 94
thread 7 setting threadInt to 60
thread 8 setting threadInt to 11
thread 9 setting threadInt to 81
thread 5 finished: 46
thread 2 finished: 11
thread 4 finished: 67
thread 3 finished: 84
thread 9 finished: 81
thread 6 finished: 94
thread 7 finished: 60
thread 1 finished: 97
thread 8 finished: 11
thread 0 finished: 88

The second 'half' the output is as expected (which I suppose means that the ThreadStatic field is working like I thought), but it seems like a few of the initial outputs have been 'skipped' from the first 'half'.

Additionally, the threads in the first 'half' are out of order, but I understand that a thread does not immediately run as soon as you call Start(); but instead the internal OS controls will be starting the threads as it sees fit. EDIT: No they're not, actually, I just thought they were because my brain misses the consecutive numbers


So, my question is: What's going wrong to cause me to lose a few lines in the first 'half' of the output? For example, where is the line 'thread 3 setting threadInt to 84'?

解决方案

Threads are executing at the same time. What conceptually happens is this:

staticVolatileTestString += Environment.NewLine + "\tthread " + ((int) o) + " setting threadInt to " + newVal;

  1. Thread 1 reads staticVolatileTestString
  2. Thread 2 reads staticVolatileTestString
  3. Thread 3 reads staticVolatileTestString
  4. Thread 1 appends the stuff and writes staticVolatileTestString back
  5. Thread 2 appends the stuff and writes staticVolatileTestString back
  6. Thread 3 appends the stuff and writes staticVolatileTestString back

That causes your lines to be lost. Volatile doesn't help here; the whole process of concatenating the string is not atomic. You need to use a lock around those operations:

private static object sync = new object();

lock (sync) {
    staticVolatileTestString += Environment.NewLine + "\tthread " + ((int) o) + " setting threadInt to " + newVal;
}

这篇关于C#ThreadStatic +挥发性成员未按预期的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆