2017-06-22 98 views
0

我一直在开发多线程算法,我对C#中的线程之间共享类成员存在一些疑问。C#:在线程之间共享类成员

我们假设我们有两个类Algorithm和Processor。处理器有一个 主要方法DoWork和其他可用资源方法偶尔调用以更改可用资源的数量进行处理。 方法运行UpdateResources算法对象由两个不同的线程调用,可能在不同核心上的工作。

是否有可能是_processor变量将被存储在CPU的缓存,绝不会被上传到内存中,并AvaliableResources将永远不会被调用,因为_processor是空的第二个线程?

class Processor 
{ 

    public void DoWork() { ... } 
    public void AvaliableResources(int x) { ... } 
} 

class Algorithm 
{ 
    private Processor _processor; 

    public void Run() 
    { 
     _processor = new Processor(); 
     _processor.DoWork(); 
     _processor = null; 
    } 

    public void UpdateResources(int x) 
    { 
     _processor?.AvaliableResources(x); 
    } 
} 

如果有一个同步的问题将下面的代码是为它的解决方案?

替代1

class Processor 
{ 
    public void DoWork() { ... } 
    public void UpdateResources(int x) { ... } 
} 

class Algorithm 
{ 
    private volatile Processor _processor; // added volatile keyword 

    public void Run() 
    { 
     _processor = new Processor(); 
     _processor.DoWork(); 
     _processor = null; 
    } 

    public void UpdateResources(int x) 
    { 
     _processor?.UpdateResources(x); 
    } 
} 

替代2

class Processor 
{ 
    public void DoWork() { ... } 
    public void UpdateResources(int x) { ... } 
} 

class Algorithm 
{ 
    private Processor _processor; 

    public void Run() 
    { 
     _processor = new Processor(); 
     Thread.MemoryBarrier(); // Added memory barier 
     _processor.DoWork(); 
     _processor = null; 
    } 

    public void UpdateResources(int x) 
    { 
     Thread.MemoryBarrier(); // Added memory barier 
     _processor?.UpdateResources(x); 
    } 
} 

编辑: 正如您在留言建议,请参阅更好地解释代码:

class Processor 
    { 
     private int resources = Environment.ProcessorCount; 

     public void DoWork() 
     { 
      /*do some long running job using avaliable resources*/ 
     } 

     public void UpdateResources(int x) 
     { 
      resources = x; 
     } 
    } 

    class Algorithm 
    { 
     private volatile Processor _processor; 

     public void Run() 
     { 
      _processor = new Processor(); 
      _processor.DoWork(); 
      _processor = null; 
     } 

     public void UpdateResources(int x) 
     { 
      _processor?.UpdateResources(x); 
     } 
    } 

    class Program 
    { 
     static void Main(string[] args) 
     { 
      var algorithm = new Algorithm(); 
      var result = Task.Run(() => algorithm.Run()); 
      // The resources were required for other staff and are reduced 
      algorithm.UpdateResources(1); 
      // The resources are reassigned for the long running algorithm 
      algorithm.UpdateResources(10); 
      // wait until the algorithm finishes 
      result.Wait(); 
      // this update should have no effect as the Run method has finished and _processor is null 
      algorithm.UpdateResources(10); 
     } 
    } 
+0

当你运行代码时发生了什么? – Fabulous

+0

另外考虑如果https://stackoverflow.com/questions/3556351/why-we-need-thread-memorybarrier没有解决您的查询 – Fabulous

+0

“的第二个线程” - 既不是线程是第一或第二个 - 他们只是不同的线程;在“Run”甚至被调用之前,“第二个”线程可以完成它所需的一切......在这种情况下:“_processor”的值是多少? –

回答

0

如果您希望以这种方式访问​​__processor obj,则2选项是错误的。

以任何方式,你应该在处理器null,因为DoWork的运行,并更快地完成。 尝试查找与睡眠相同的第一个线程,并检查是否可用已执行。

您的代码没有提供足够的信息来建议正确的方法。

是正确使用volatile关键字,但如果运行速度快可以不叫永远

编辑

好,很好的例子。但问题是执行UpdateResources之前Run Run的主要工作人员。

如果您希望UpdateResources在等待之前执行两次,您会在等待后插入执行_processor= null的新方法。 以某种方式每一个这样的代码,每次您在等待之前调用UpdateResources,您的风险是_processor为null。

取决于你在等待之前想要什么

+1

'volatile'是一个非常微妙和细微的野兽;大多数人认为“volatile”的“效应”实际上只是次要副作用和实现细节。要求任何人定义'volatile'*实际上意味着什么*,以及这对特定情况有何帮助,......是的,除了少数CPU专家外,大多数人无法给出一个好答案。我把自己包括在“无法给出一个好答案”的组中。 –

+0

我不明白你想用这个线程做什么。如果你想为你的问题或其他问题的提示。易失性用于变量中总是最新的更新值。此关键字与编译器交流以优化多线程访问的值。无论如何,如果运行完成,代码不会执行更新资源。只有在执行doWork时调用方法更新资源 – Pasalino

+0

@Pasalino我已经添加了更好的示例,我希望它会有所帮助。 –