staticVolatileTestString

staticVolatileTestString

我正在阅读tips and tricks帖子,我认为我会尝试一些以前从未做过的C#工作。因此,以下代码没有实际目的,而只是查看所发生情况的“测试功能”。

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

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

如您所见,我正在测试 ThreadStaticAttribute volatile 关键字。

无论如何,我有一个如下所示的测试方法:
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;
}

我希望从该函数返回的结果是这样的输出:
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

但是,我得到的是:
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

第二个“一半”的输出是预期的(我想这意味着ThreadStatic字段的工作与我想象的一样),但是似乎一些初始输出已从第一个“一半”“跳过”了。

另外,第一个“一半”中的线程是乱序的,但是我知道一旦调用Start(),线程不会立即运行。但相反,内部OS控件将根据需要启动线程。
编辑:不,他们不是,实际上,我只是以为是因为我的大脑错过了连续的数字

因此,我的问题是:出了什么问题导致我在输出的前半个部分丢失了几行?例如,“线程3将threadInt设置为84”行在哪里?

最佳答案

线程正在同时执行。从概念上讲,这是这样的:

staticVolatileTestString += Environment.NewLine + "\tthread " + ((int) o) + " setting threadInt to " + newVal;
  • 线程1读取staticVolatileTestString
  • 线程2读取staticVolatileTestString
  • 线程3读取staticVolatileTestString
  • 线程1附加了这些内容,并将staticVolatileTestString写回
  • 线程2附加了这些内容,并将staticVolatileTestString写回
  • 线程3附加了这些内容,并将staticVolatileTestString写回

  • 这会导致您的线路丢失。 volatile 在这里无济于事;连接字符串的整个过程不是原子的。您需要在这些操作周围使用锁:
    private static object sync = new object();
    
    lock (sync) {
        staticVolatileTestString += Environment.NewLine + "\tthread " + ((int) o) + " setting threadInt to " + newVal;
    }
    

    关于c# - C#ThreadStatic + volatile成员未按预期工作,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/10993574/

    10-10 17:58