Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/windows/14.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# “可以”;AutoResetEven';s Waitone();在停止windows服务时制造障碍?_C#_Windows_Multithreading - Fatal编程技术网

C# “可以”;AutoResetEven';s Waitone();在停止windows服务时制造障碍?

C# “可以”;AutoResetEven';s Waitone();在停止windows服务时制造障碍?,c#,windows,multithreading,C#,Windows,Multithreading,在我的windows服务中,我启动了5个独立工作的线程,它们不编写公共资源(因此没有互斥或死锁) 但是一个线程有一个自动resetEvent\u waitTillusBinstered.WaitOne()调用。基本上,该线程负责在插入USB后立即启动USB文件传输,因此它会等待直到从负责监视USB插入/删除事件的线程接收到通知信号(通过设置\u waitTillusBinstered,即调用\u waitTillusBinstered.Set()) 问题:是否可能因为\u waitTillusB

在我的windows服务中,我启动了5个独立工作的线程,它们不编写公共资源(因此没有互斥或死锁)

但是一个线程有一个
自动resetEvent
\u waitTillusBinstered.WaitOne()
调用。基本上,该线程负责在插入USB后立即启动USB文件传输,因此它会等待直到从负责监视USB插入/删除事件的线程接收到通知信号(通过设置
\u waitTillusBinstered
,即调用
\u waitTillusBinstered.Set()

问题:是否可能因为
\u waitTillusBinstered.WaitOne()
,我的windows服务不会停止


询问原因:我试图通过windows服务管理器工具停止windows服务(按“停止”),但它无法停止服务(出现错误1053)。我终于不得不重新启动我的电脑。它一次又一次地发生(4-5次)。我注释掉了所有启动调用的线程,然后我可以停止我的windows服务。我取消了所有启动调用的线程的注释,但现在我可以停止windows服务(不做任何更改)。我无法重现该条件,但我怀疑原因可能是
\u waitTillusBinstered.WaitOne()

如果您的线程是前台线程,并且您没有使用EventWaitHandle.WaitOne(Int32),那么是:该线程是前台线程,它会阻止进程终止,直到线程终止,然后等待一个()阻止线程,防止其终止

发件人:

线程可以是背景线程,也可以是前景线程。 背景线程与前景线程相同,只是 后台线程不阻止进程终止。一劳永逸 属于进程的前台线程已终止,公共 语言运行库结束该过程。任何剩余的后台线程 已停止且未完成。默认情况下,以下线程 在前台执行(即,其IsBackground属性 返回false):

  • 主线程(或主应用程序线程)
  • 通过调用线程类构造函数创建的所有线程
使用线程构造函数创建的任何线程,除非 通过使用IsBackground属性专门配置的 前台线程,并将阻止进程终止,直到 终止

阻止当前线程,直到当前WaitHandle收到 信号

有几种方法可以缓解这个问题。 首先:如果你能忍受线程过早终止,那么像这样构造线程:

var thread = new Thread(ThreadStart)
{
    IsBackground = true
}
当服务终止时,进程将正确退出,尽管线程正在阻止WaitHandle.WaitOne()调用

第二种方法是使用某种状态(通过引用传递)通知线程它应该终止。以下示例使用CancellationToken

using System.ServiceProcess;
using System.Threading;

public class ServiceState
{
    public ServiceState(CancellationToken cancellationToken, WaitHandle waitHandle)
    {
        this.CancellationToken = cancellationToken;
        this.WaitHandle = waitHandle;
    }

    public CancellationToken CancellationToken { get; }

    public WaitHandle WaitHandle { get; }
}

public class MyService : ServiceBase
{
    private readonly Thread serviceThread;
    private readonly CancellationTokenSource cancellationTokenSource;
    private readonly WaitHandle waitHandle;

    public Service()
    {
        serviceThread = new Thread(ThreadProc);
        cancellationTokenSource = new CancellationTokenSource();
        waitHandle = new EventWaitHandle(false, EventResetMode.AutoReset);
    }

    protected override void OnStart(string[] args)
    {
        var state = new ServiceState(cancellationTokenSource.Token, waitHandle);
        serviceThread.Start(state);
    }

    protected override void OnStop()
    {
        cancellationTokenSource.Cancel();
        waitHandle.Set();
    }

    private static void ThreadProc(object state)
    {
        var serviceState = (ServiceState)state;

        do
        {
            serviceState.WaitHandle.WaitOne();
            if (serviceState.CancellationToken.IsCancellationRequested)
            {
                return; // This will terminate the thread.
            }

            // Thread logic goes here.
        } while (true);
    }
}

由您定义停止状态的含义。但是您肯定应该使用WaitAny(),这样当用户停止服务时线程也可以完成。这不是绝对必要的,您也可以忽略USB插入,或者在服务未激活时不使用USB设备。在OnStop事件中是否有任何内容?@ThingyWhat Windows中的服务只不过是在特殊上下文(服务控制管理器)中启动的可执行文件。由于所讨论的服务是一个.NET可执行文件,我们获得了.NET运行时的好处和含义,包括托管线程,它们遵循我在回答中提到的规则(前台与后台)。在前台线程和后台线程的上下文中,区别在于一个(前台)将阻止进程终止,而另一个(后台)将不会。OK-默认值必须是后台,然后,(否则我的C#服务将遇到麻烦:)。文档中明确指出,主线程以及通过new thread()创建的线程都是前台线程,除非您显式地将IsBackground设置为true。如果您使用的是线程池,那么这些线程都将是后台线程。