Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/311.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 优雅地关闭工作线程_C#_.net_Concurrency_Multithreading - Fatal编程技术网

C# 优雅地关闭工作线程

C# 优雅地关闭工作线程,c#,.net,concurrency,multithreading,C#,.net,Concurrency,Multithreading,我不明白为什么在这个实现中,stopped不是volatile——如果一个不同的线程更新了它,它会正确地反映出来吗 第二,测试(!Stopping)是原子的吗 使用系统; 使用系统线程; /// ///工作线程的骨架。通常会设置另一个线程 ///一个有一些工作要做的实例,并调用Run方法(例如 ///新线程(新线程开始(job.Run)).Start()) /// 公社工人 { /// ///锁盖停止和停止 /// 只读对象stopLock=新对象(); /// ///是否已要求工作线

我不明白为什么在这个实现中,
stopped
不是
volatile
——如果一个不同的线程更新了它,它会正确地反映出来吗

第二,测试(
!Stopping
)是原子的吗

使用系统;
使用系统线程;
/// 
///工作线程的骨架。通常会设置另一个线程
///一个有一些工作要做的实例,并调用Run方法(例如
///新线程(新线程开始(job.Run)).Start())
/// 
公社工人
{
/// 
///锁盖停止和停止
/// 
只读对象stopLock=新对象();
/// 
///是否已要求工作线程停止
/// 
布尔停止=假;
/// 
///工作线程是否已停止
/// 
bool-stopped=false;
/// 
///返回是否已要求工作线程停止。
///即使在线程停止后,它仍会继续返回true。
/// 
公共停车场
{
得到
{
锁(止动锁)
{
回程停车;
}
}
}
/// 
///返回工作线程是否已停止。
/// 
公共广播停止了
{
得到
{
锁(止动锁)
{
返回停止;
}
}
}
/// 
///通知工作线程停止,通常在完成其
///当前工作项。(线程*不*保证已停止。)
///当此方法返回时。)
/// 
公共停车场()
{
锁(止动锁)
{
停止=真;
}
}
/// 
///由工作线程调用以指示其何时停止。
/// 
无效
{
锁(止动锁)
{
停止=真;
}
}
/// 
///本课程的主要工作循环。
/// 
公开募捐
{
尝试
{
当(!停止)
{
//在这里插入工作。确保它不会出现紧密循环!
//(如果工作定期到达,使用队列和监视器。等待,
//更改停止方法以使监视器脉冲以及设置
//停下来。)
//请注意,您可能还希望在循环中突破
//如果工作项可能需要很长的时间,但有
//检查你是否被要求停止是有意义的。
//只需执行以下操作:
//如果(停止)
// {
//返回;
// }
//finally块将确保设置了stopped标志。
}
}
最后
{
SetStopped();
}
}
}
编辑


此代码来自

因为它只能在
锁内访问。
lock
还可以确保您看到最新的值


重原子性(我想你真的是指这里的同步?);这没有什么困难;即使
停止
是同步的,我们也不能再相信一旦我们退出我们拥有的
,该值就是最新的。因此
!停止
与停止
的同步性不一样。重要的是我们知道我们至少最近检查过了。有一种边缘情况,即标志在我们检查之后被更改,但这很好:当我们检查时,我们确实应该继续。

请参阅。它解释了为什么锁优先于volatile。

此代码的行为在C语言规范的第3.10节中定义:

C#程序的执行过程是这样进行的,即每个执行线程的副作用都保留在关键执行点。副作用定义为对易失性字段的读取或写入、对非易失性变量的写入、对外部资源的写入以及引发异常。必须保留这些副作用顺序的关键执行点是对易失性字段(§10.5.3)、锁定语句(§8.12)以及线程创建和终止的引用

换句话说,lock语句足以保证避免声明stopped字段为volatile


JIT编译器如何实现此规则是一个有趣的问题,因为lock语句只调用Monitor.Enter()和Exit()方法。我不认为它对这些方法有什么特别的了解,我认为这是输入在Enter()调用之后开始的try块的副作用。但这只是一个猜测。

我不明白,Jon Skeet是如何关联的?@s.Mark:Its'来自Jon Skeets页面关于关闭工作线程的内容。@s.Mark…任何与编程相关的内容都与Jon Skeet有关……这应该是Jon Skeet的事实!但是这个例子不属于链接条目中的“volatile实际上有什么好处”类别吗?没有方法将stopped或stopping设置为false,因此不可能存在任何竞争条件。我理解这一点了吗?每次获得一个锁时,寄存器都会被刷新,并且您从不读取过时的值?换言之,如果我在一个紧循环中获得一个锁,那么我不需要volatile?曾经吗?只要所有其他线程仅在持有(相同)锁时更新字段,则是。如果其他线程在未获得锁的情况下更新字段,则所有下注都将取消。
using System;
using System.Threading;

/// <summary>
/// Skeleton for a worker thread. Another thread would typically set up
/// an instance with some work to do, and invoke the Run method (eg with
/// new Thread(new ThreadStart(job.Run)).Start())
/// </summary>
public class Worker
{
    /// <summary>
    /// Lock covering stopping and stopped
    /// </summary>
    readonly object stopLock = new object();
    /// <summary>
    /// Whether or not the worker thread has been asked to stop
    /// </summary>
    bool stopping = false;
     /// <summary>
    /// Whether or not the worker thread has stopped
    /// </summary>
    bool stopped = false;

    /// <summary>
    /// Returns whether the worker thread has been asked to stop.
    /// This continues to return true even after the thread has stopped.
    /// </summary>
    public bool Stopping
    {
        get
        {
            lock (stopLock)
            {
                return stopping;
            }
        }
    }

    /// <summary>
    /// Returns whether the worker thread has stopped.
    /// </summary>
    public bool Stopped
    {
        get
        {
            lock (stopLock)
            {
                return stopped;
            }
        }
    }

    /// <summary>
    /// Tells the worker thread to stop, typically after completing its 
    /// current work item. (The thread is *not* guaranteed to have stopped
    /// by the time this method returns.)
    /// </summary>
    public void Stop()
    {
        lock (stopLock)
        {
            stopping = true;
        }
    }

    /// <summary>
    /// Called by the worker thread to indicate when it has stopped.
    /// </summary>
    void SetStopped()
    {
        lock (stopLock)
        {
            stopped = true;
        }
    }

    /// <summary>
    /// Main work loop of the class.
    /// </summary>
    public void Run()
    {
        try
        {
            while (!Stopping)
            {
                // Insert work here. Make sure it doesn't tight loop!
                // (If work is arriving periodically, use a queue and Monitor.Wait,
                // changing the Stop method to pulse the monitor as well as setting
                // stopping.)

                // Note that you may also wish to break out *within* the loop
                // if work items can take a very long time but have points at which
                // it makes sense to check whether or not you've been asked to stop.
                // Do this with just:
                // if (Stopping)
                // {
                //     return;
                // }
                // The finally block will make sure that the stopped flag is set.
            }
        }
        finally
        {
            SetStopped();
        }
    }
}