【问题标题】:Sending a thread into dormant state till an event occurs将线程发送到休眠状态直到事件发生
【发布时间】:2017-03-13 11:48:50
【问题描述】:

我有一个带有 2 个线程的多线程程序。

一个线程正在检测 USB 插入和拔出。

第二个线程负责将文件传输到 USB(在 USB 插入事件中)。一旦所有文件都成功复制到 USB 然后,文件复制线程(第二个线程)应该进入“成功复制”状态并保持在那里直到USB被移除。移除 USB 后,isUSBInsterted 标志设置为 FALSE,文件复制线程(第二个线程)进入空闲状态。

 public enum FileTransferStates { Idle = 0, FileCopyingState = 1, SuccessfullyCopiedState = 2 }

    public void ExecuteUSBFileTransfer()
    {
        switch (CurrentState)
        {
            case FileTransferStates.Idle:
                IdleState();
                return;


            case FileTransferStates.FileCopyingState:

                FileCopyingState();
                ExecuteUSBFileTransfer();
                break;

            case FileTransferStates.SuccessfullyCopiedState:

                SuccessfullyCopiedState();
                ExecuteUSBFileTransfer();
                break;

            default:
                return;
        }
    }

    private void SuccessfullyCopiedState()
    {
       //Current state is "FileTransferStates.SuccessfullyCopiedState"

        if (!USB.isUSBInsterted)
            CurrentState = FileTransferStates.Idle; //Resetting the State if the USB is removed        
    }

问题:目前,如果线程已进入SuccessfullyCopiedState(),我会一次又一次地调用父方法(ExecuteUSBFileTransfer() )。我认为这是对 CPU 资源的浪费。此外,USB 可能会长时间保持插入状态。所以,我希望线程在这段时间内休眠,直到 USB 未被移除。我怎样才能留在SuccessfullyCopiedState() 而不检查 USB 移除而不浪费资源?

PS:基本上,我想将文件复制线程发送到SuccessfullyCopiedState()方法内的休眠阶段,直到USB没有被移除。

【问题讨论】:

  • 根据伪代码很难回答这个问题。你知道阻塞和非阻塞 I/O 的区别吗?你知道 select() 作为等待输入和/或信号的低级方式吗?您的库是否有一个等待事件发生的方法?你的图书馆有回调吗?回调在哪个线程中执行?你知道线程和互斥体以及 Wait() 和 Notify() 吗?
  • 顺便说一句。为什么第一个方法递归调用自己?这是通过递归来模拟事件循环的尝试吗?调用是结束递归的,但我认为.net 没有结束递归优化,或者有吗?通常,事件循环是通过循环实现的,因此得名 ^^.
  • @yeoman:我没有使用任何外部库。两个线程(USB 和 FileCopyingThread)都由 Main 函数(püublic static void main())启动。我知道有关线程和互斥锁的基本概念。我需要来自 USB 线程的全局通知,即 USB 已被移除,并且 FileCopyingThread 应该休眠直到它收到此通知。
  • @yeoman:第一种方法是递归调用自身......这就是我问这个问题的原因。如果我的线程可以休眠直到收到 USB 已收到的通知,那么我不需要一次又一次地输入private void SuccessfullyCopiedState()

标签: c# multithreading


【解决方案1】:

您正在寻找:

AutoResetEvent (ManualResetEvent)

简单地说:这些将允许您“冻结”一个线程,直到它收到来自另一个线程的“go”。

Eren Ersönmez 在另一个问题的答案中有完整的example,它使用 2 个 Worker 线程,但仍然很容易掌握。

基本上你有这个AutoResetEvent 对象,当你调用.WaitOne() 时它会阻塞线程的执行。一旦你从任何你喜欢的线程调用.Set(),这个“块”就会被重置。

例子:

static readonly AutoResetEvent fileCopyEvent = new AutoResetEvent(false);

bool keepFileCopyThreadAlive = true;
void FileCopyThread()
{
    while (keepFileCopyThreadAlive)
    {
        fileCopyEvent.WaitOne(); 
        if (!keepFileCopyThreadAlive) return; // Exit thread if told to.
        Console.WriteLine("Copying files...");
        Thread.Sleep(1000); // Do your stuff here
        Console.WriteLine("Done copying files, waiting for USB Thread.");
    }
}

此时,您所要做的就是从您的 USB 线程中调用:fileCopyEvent.Set();。 这将释放“块”并执行fileCopyEvent.WaitOne(); 以下的任何内容。由于这是一个AutoResetEvent 对象,它将自动返回其“阻塞”状态,您无需执行任何其他操作。该循环将强制代码返回到.WaitOne(),并为您下次调用.Set()做好准备。

退出线程就像设置keepFileCopyThreadAlive = false; 然后调用通常的.Set() 一样简单。因为有一个检查退出循环一次keepFileCopyThreadAlive == false

注意:以上代码未经测试,目前没有可用的编译器。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-02
    • 1970-01-01
    • 1970-01-01
    • 2012-06-14
    • 2010-09-24
    • 1970-01-01
    相关资源
    最近更新 更多