gpt4 book ai didi

c# - Windows 服务是否需要确保命令可以在不同的线程上处理?

转载 作者:太空狗 更新时间:2023-10-29 23:39:25 29 4
gpt4 key购买 nike

当通过服务控制管理器运行时,Windows 服务是否需要假定可以在不同线程上调用命令处理方法(OnStart、OnStop 等),而无需确保,例如,对成员的分配在方法之间可见?

public class MyService : ServiceBase {

private Object _foo;

protected override void OnStart(string[] args) {
_foo = new Object();
}

protected override void OnStop() {
if (_foo == null) {
throw new Exception("Assignment not visible"); // Can this happen?
}

_foo = null;
}

}

我无法保证我的示例中的异常不会被抛出,但是我找到的所有示例,包括 elsewhere on StackOverflow ,似乎假设,例如,在 OnStart() 中对变量的赋值在 OnStop() 中始终可见。

如果 SCM 没有做出这样的保证,我确实知道如何确保分配可见(例如,通过在服务中的所有读/写周围添加一个锁)。我感兴趣的是这些措施是否有必要。

最佳答案

从某种意义上说,SCM 不能保证您概述的异常不会被抛出。当然,它不控制服务对私有(private)成员的操纵——例如如果附加服务代码影响 _foo

话虽如此,请考虑以下场景,看看为什么您的特定问题的答案显然是否定的:

1) 使用以下更改来构建您的服务以进行演示:

    public partial class MyService : ServiceBase
{
private Object _foo;
private const string _logName = "MyService Log.txt"; // to support added logging

public MyService()
{
InitializeComponent();
}

protected override void OnStart(string[] args)
{
// demonstrative logging
var threadId = Thread.CurrentThread.ManagedThreadId;
using (var log = new StreamWriter(AppDomain.CurrentDomain.BaseDirectory + _logName, true))
{
log.WriteLine("{0}: In OnStart(string[]) on thread ID {1}. Sleeping for 10 seconds...", DateTime.Now, threadId);
}

// Sleep before initializing _foo to allow calling OnStop before OnStart completes unless the SCM synchronizes calls to the methods.
Thread.Sleep(10000);

_foo = new Object();
}

protected override void OnStop()
{
// demonstrative logging added
var threadId = Thread.CurrentThread.ManagedThreadId;
using (var log = new StreamWriter(AppDomain.CurrentDomain.BaseDirectory + _logName, true))
{
log.WriteLine("{0}: In OnStop() on thread ID {1}.", DateTime.Now, threadId);
}

if (_foo == null)
{
// demonstrative logging added
using (var log = new StreamWriter(AppDomain.CurrentDomain.BaseDirectory + _logName, true))
{
log.WriteLine("{0}: _foo == null", DateTime.Now);
}

throw new Exception("Assignment not visible"); // Can this happen?
}

_foo = null;
}
}

2) 打开命令外壳。

3) 打开另一个命令外壳。

4) 在第一个命令 shell 中,安装服务(使用 sc create)(如果您还没有),然后启动它(使用 net start)。你应该看到:

The MyService service is starting.....

当 SCM 等待 10 秒休眠以启动服务时,尾随点应该被一个接一个地添加。

5) 在第二个命令 shell 中,尝试在 10 秒之前停止服务(使用 net stop)。你应该看到:

The service is starting or stopping. Please try again later.

因此启动服务显然是一个阻塞操作,必须在服务停止之前完成。

6) 10 秒后检查第一个命令 shell。你应该看到:

The MyService service was started successfully.

7) 返回到第二个命令shell,再次尝试停止服务。你应该看到:

The MyService service is stopping.

The MyService service was stopped successfully.

8) 查看生成的日志 - 例如:

10/22/2013 7:28:55 AM: In OnStart(string[]) on thread ID 4. Sleeping for 10 seconds...

10/22/2013 7:29:17 AM: In OnStop() on thread ID 5.

我认为使用两个命令 shell 可以更轻松地快速启动和停止服务;但该示例也同样适用于一个命令 shell。

最后,您可能会找到 Mitchell Taylor (CoolDadTx) 对 a similar question in MSDN forums 的回答和我一样有趣:

The threading model used by the SCM isn't formally documented AFAIK. What is known is that each service gets called on its own thread. However the SCM might or might not use a thread pool to reuse a thread across services. When a service is called (start, stop, custom commands, etc) it is expected to perform its task and return quickly. There is a strong limit on how long it can take. Anything more than a quick return requires that you push the request to a secondary thread for processing. The SCM itself runs on a separate thread so if a service takes too long to respond then the SCM sees it as hung. This is discussed here: http://msdn.microsoft.com/en-us/library/ms684264(VS.85).aspx

更新:

特别注意 Service State Transitions Mitchell Taylor 引用的文章链接到的 MSDN 文章。它包含一个状态图,非常清楚和权威地记录了定义的服务状态转换,并与我上面概述的内容保持一致。它还结合状态图解释了 SCM 如何不时不时地传输服务控制请求以确保仅定义的状态转换。

关于c# - Windows 服务是否需要确保命令可以在不同的线程上处理?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18433023/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com