c#工作线程中的While循环用于监听命令和响应

本文关键字:监听 用于 命令 响应 循环 While 工作 线程 | 更新日期: 2023-09-27 18:16:32

问题概述:

我尝试使用线程(while..loop)来监听来自用户的命令。如果用户发送命令,它将在类(LoopingWorkerThread)中的全局变量中分配新值。

我不明白,如果我不把线程睡眠值低于10毫秒,我不会得到任何响应(它是在ListenCommand方法)。看起来全局参数在方法中被覆盖了"_CommandReceived",可能处理器运行得太快而忽略了参数的值已经改变了("_CommandReceived")。

如果有更好的机制请评论。我必须在ListenCommand while循环中锁定它

代码如下:

public class LoopingWorkerThread
    {
        /// <summary>
        /// Local main thread for LoopingWorkerThread
        /// </summary>
        private Thread t;
        /// <summary>
        /// Local parameter to identify the LoopingWorkerThread Is On
        /// </summary>
        private bool _IsOn;
        /// <summary>
        /// Local parameter to store command received from user
        /// </summary>
        private int _CommandReceived;
        /// <summary>
        /// Local object to use for locking the LoopingWorker Thread
        /// </summary>
        private object _LockListenCommand = new object();
        /// <summary>
        /// Properties of LoopingWorker Thread Is On
        /// </summary>
        public bool IsOn
        {
            get { return _IsOn; }
            set { _IsOn = value; }
        }
        /// <summary>
        /// Property of storing the command received from user
        /// </summary>
        public int CommandReceived
        {
            get { return _CommandReceived; }
            set { _CommandReceived = value; }
        }
        /// <summary>
        /// Delegate for OnResponse Event Handler
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public delegate void OnResponseHandler(object sender, ResponseArg e);
        /// <summary>
        /// Event of OnResponse
        /// </summary>
        public event OnResponseHandler OnResponse;
        /// <summary>
        /// Constructor of LoopingWorkerThread Class
        /// </summary>
        public LoopingWorkerThread()
        {
            _IsOn = false;
        }
        /// <summary>
        /// Method of LoopingWorkerThread Function
        /// </summary>
        private void ListenCommand()
        {
            lock (_LockListenCommand)
                while (_IsOn)
                {
                    switch (_CommandReceived)
                    {
                        case 0:
                            // Ignore default command
                            break;
                        case 1:
                            FireOnResponse("Received cmd 1, response [Hello One]");
                            break;
                        case 2:
                            FireOnResponse("Received cmd 2, response [Hello Two]");
                            break;
                        default:
                            FireOnResponse("Error. Received unidentified command - " + _CommandReceived.ToString());
                            break;
                    }
                    //Console.WriteLine("ThreadProc: Cmd:[{0}] - Response:{1}", _CommandReceived.ToString(), ReaderResponse);
                    // Reset or Clear the Command Received
                    _CommandReceived = 0;
                    // If the sleep less than 10 millisecond, it always don't catch the 
                    // command received which assigned to 1 or 2. Don't understand, or is there
                    // any better method.
                    **Thread.Sleep(10);**
                }
        }
        /// <summary>
        /// Function of firing response event back to user
        /// </summary>
        /// <param name="message"></param>
        private void FireOnResponse(string message)
        {
            ResponseArg myarg = new ResponseArg(message);
            if (OnResponse != null)
                OnResponse(this, myarg);
        }
        /// <summary>
        /// Method of starting the LoopingWorkerThread
        /// </summary>
        public void Start()
        {
            _IsOn = true;
            FireOnResponse("Main thread: Started.");
            // The constructor for the Thread class requires a ThreadStart 
            // delegate that represents the method to be executed on the 
            // thread.  C# simplifies the creation of this delegate.
            t = new Thread(new ThreadStart(ListenCommand));
            // Start ThreadProc.  Note that on a uniprocessor, the new 
            // thread does not get any processor time until the main thread 
            // is preempted or yields.  Uncomment the Thread.Sleep that 
            // follows t.Start() to see the difference.
            t.Start();
            //Thread.Sleep(0);
            FireOnResponse("Main thread: Call Start().");
        }
        /// <summary>
        /// Method of stopping the LoopingWorkerThread
        /// </summary>
        public void Stop()
        {
            _IsOn = false;
            t.Join();
            //t.Abort();
            FireOnResponse("LoopingWorker Thread is stopped.");
        }
        /// <summary>
        /// Method of sending command to the LoopingWorkerThread
        /// </summary>
        /// <param name="readercmd"></param>
        public void SendCommand(int readercmd)
        {
            _CommandReceived = readercmd;
        }
    }

c#工作线程中的While循环用于监听命令和响应

您的代码工作是因为Thread.Sleep产生了正确读取_commandReceived所需的必要内存屏障。如果你删除了Thread.Sleep调用,那么你也删除了隐式内存屏障。显然,这并不是一个值得依赖的好机制。

更重要的是,你做这件事的方式是错误的。您应该使用的是生产者-消费者模式。这对于BlockingCollection类来说非常容易,因为当队列为空时,它会阻塞Take上的消费者。

public class Example
{
  private BlockingCollection<int> commands = new BlockingCollection<int>();
  public Example()
  {
    var thread = new Thread(Run);
    thread.IsBackground = true;
    thread.Start();
  }
  public void SendCommmand(int command)
  {
    commands.Add(command);
  }
  private void Run()
  {
    while (true)
    {
      int command = commands.Take();
      ProcessCommand(command);      
    }
  }
  private void ProcessCommand(int command)
  {
    // Process the command here.
  }
}

BlockingCollection作为Reactive Extensions下载的一部分在3.5版本中可用。

尝试声明变量为volatile。更多信息请访问http://msdn.microsoft.com/en-us/library/x13ttww7.aspx