通过来自多个线程的静态类进行数据库访问

时间:2013-10-14 19:06:02

标签: c# multithreading class static thread-safety

我是一名自学成才的C#程序员,在对事情有一个非常透彻的了解时,我已经错过了一些内容,现在我偶然发现了一些我无法找到的东西。在SO上回答。我试图更好地理解C#中的线程安全性,但让我先指​​定上下文。

我目前正在开发一种Windows服务,该服务会根据SQL Server数据库中的计划进行一些监视工作。它将通过向多个“客户端服务器”发出http请求来监视某些服务器,安装在这些服务器上的客户端将使用所请求的信息进行响应。

由于此监视器服务可能会非常繁忙,因此我已将其设置为在计划完成工作时将每个“预定指令”粘贴到新线程中。这是为了确保我的计时器保持良好的顺序,准备启动到下一个“客户端服务器”的下一条指令。

每条指令的一部分是必须登录已成功执行的数据库以及响应是什么等等。现在我在我的监视器服务中有一个public static class Logger,我相信这很方便,因为我现在可以轻松地调用它Logger.Log(... )每当我需要记录事物时。此类日志记录在此类中通过EF进入SQL Server数据库。

对我而言,这听起来真的很酷,而且我对这一切的运作方式感到非常满意,但我还没有测试任何东西。我所有这一切的问题是我的大脑告诉我,因为我的记录器类是静态的 - 并且根据我的理解因此它只被实例化一次? - 如果多于1个线程试图调用Logger.Log(.. )在同一时间,我的监控服务会发生不好的事情。

这里有人可以开导我吗?我的想法是对还是错?如果你知道答案,请清楚解释,因为我很乐意理解它。 :)

更新

感谢到目前为止的回复,事情变得越来越清晰,因为人们正在询问有关Log方法的更多细节,而我现在不在我的开发PC上,我将尝试解释这种方式它的工作原理更为详细。

所有Log方法都是基于来自某些先前实例化对象的数据通过EF向SQL数据库添加记录,这些对象作为参数传递给方法。数据库上下文被实例化为静态类上的静态私有变量。这样做的原因是我不必继续在我的重载中使用语句。

3 个答案:

答案 0 :(得分:3)

static 提供了危险代码的机会,但并不能保证。如果您使用的是static类/方法,则必须注意不要使用任何实例数据。

这对您的情况意味着什么?基本上,您希望在DbContext方法中实例化Log,进行日志记录,Dispose DbContext(在using语句中包含用法) 。只要没有共享实例数据,您就可以了。

但是,如果您在静态构造函数中执行某些操作或使用类级变量,则可能会产生问题。

修改:在您的具体情况下,您不应在所有主题中共享DbContext。请查看here,了解DbContext的正确范围。它应该在每种方法中实例化。

This blog entry说明以下内容(并提供解释):

  

大多数[这些考虑因素]倾向于指向不共享的短期背景。

     

这是我推荐的经验法则。

答案 1 :(得分:3)

每个方法,无论是静态还是虚拟,都有自己的框架,因此不涉及任何线程问题。问题发生在方法实现中:一些静态方法将使用静态变量或静态资源,并且它们都是相同的管道,并且您将遇到竞争条件。但是在静态方法中声明的局部变量不是静态的,所以如果你的方法不修改静态变量或资源,你就可以了。

答案 2 :(得分:3)

Logger课程的文档在线程安全方面有何说法?关于静态类或方法,本质上线程不安全。

如果您调用的方法或属性,是否为静态

  • 引用相关方法的本地变量(例如,不引用任何实例或静态成员),
  • 创建自己需要协作的任何其他类的实例

你应该是线程安全的。请注意,在其他类中调用的任何方法或属性同样必须是线程安全的。