C#:在线程

时间:2017-06-22 22:15:23

标签: c# multithreading thread-safety clr

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

假设我们有两个类Algorithm和Processor。处理器有一个 主方法 DoWork 和其他 AvaliableResources 方法,偶尔会调用它来更改可用资源的数量以进行处理。 算法对象中的 Run UpdateResources 方法由两个不同的线程调用,可能在不同的Core上工作。< / p>

是否可能 _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);
        }
    }

1 个答案:

答案 0 :(得分:0)

如果您想要访问,则2替代方案是错误的 以这种方式_processor obj。

无论如何,处理器中应该为null,因为DoWork运行速度更快。 尝试在睡眠的第一个线程中查找相同的秒,并检查是否可以执行。

您的代码未提供足够的信息以便以正确的方式提供建议。

使用volatile关键字是正确的,但如果Run is fast available不是call never

修改

好的,好的例子。但问题是在执行UpdateResources之前运行完成的主要工作程序。

如果您想在等待之前执行两次UpdateResources,则在等待后插入执行_processor= null的新方法。 在某种程度上,每次使用此代码时,每次在等待之前调用UpdateResources,您的风险都是_processor为空。

在等待之前取决于你想要的东西