2015-09-16 62 views
5

我很难理解为什么多线程失败线程完成之前更新值。单独的线程是否有自己的引用或值的副本?
多线程问题,更新的价值

如果不是这样,我的理解下面的代码应能正常工作时的MyMethod被调用,但通常不会在thread.IsAlive之前创建数组中的一些的MyType对象的实例为假:

class MyClass 
{ 
    static MyType[] obj = new MyType[Environment.ProcessorCount - 1]; 
    void MyMethod() 
    { 
     Thread[] threads = new Thread[Environment.ProcessorCount - 1]; 

     for (int i = 0; i < Environment.ProcessorCount - 1; i++) 
     { 
      threads[i] = new Thread(() => FillObjects(i)); 
      threads[i].Priority = ThreadPriority.AboveNormal; 
      threads[i].Start(); 
     } 

     while (threads[i].Any(c => c.IsAlive)) 
     { 
      Thread.Sleep(50); 
     } 
    } 
    void FillObjects(int i) 
    { 
     obj[i] = new MyType(); 
     //perform actions with obj[i] to fill it with necessary values 
    } 
} 

回答

6

您需要循环变量的值赋给一个局部变量。否则,它可能是i在递增经过这么FillObjects(0)不会被调用,因此obj[0]从未分配的FillObjects(i)第一次执行时执行。

void MyMethod() 
{ 
    Thread[] threads = new Thread[Environment.ProcessorCount - 1]; 

    for (int i = 0; i < Environment.ProcessorCount - 1; i++) 
    { 
     int local = i; 
     threads[i] = new Thread(() => FillObjects(local)); 
     threads[i].Priority = ThreadPriority.AboveNormal; 
     threads[i].Start(); 
    } 

    while (threads.Any(c => c.IsAlive)) 
    { 
     Thread.Sleep(50); 
    } 
} 
+2

好点。如果'FillObjects()'中的第一个语句是'Thread.Sleep(1000)',可能只有'obj [Environment.ProcessorCount - 1]'是非空的,因为循环会将'i'增加到它的最终值在创建第一个对象之前。考虑一下,FillObjects()可能会抛出,因为在循环退出之前'i'实际上会增加到'Environment.ProcessorCount-1',因此超出了'obj'的范围。 –

+0

感谢您的回复,确实这是主要问题之一,现在它正确地实例化对象。然而,线程在关闭之前并未完全正确地完成所有操作,而是随机执行此操作。有什么建议么? – Almis

+0

我发现自己的逻辑错误,现在它正常工作。 – Almis

-1

在多处理器机器上(必须具有的)结果写入一个线程中的内存位置可能由于高速缓存而在另一个线程中不可见。使用Thread.VolatileReadThread.VolatileWrite读取以读取和写入“通过”高速缓存。

参看the chapter on threading in c# 3.0 in a Nutshell作出解释。 (查找问题“是否有可能在等待的方法来写‘假’?”。这个例子基本上是你的情况。)

+0

出于好奇:什么是错的或不适用我说的? –

+0

虽然不是那个downvoted的人:我想不出使用volatileRead/Write来解决上述问题的场景。从简单的恕我直言的C#引用的问题不符合上述问题,以及我没有看到任何缓存问题,挥发性将解决。 – Linky

+0

@Linky Hm。这是两个线程都访问一个静态变量。一个线程“已经写入”(由该线程后面的事件表示)。另一个线程从写入线程的角度读取已写入的值,但看不到写入。在我看来,这很像这里的场景。 –