如何确保静态类及其成员是否是线程安全的? [英] How to ensure a static class and its members are thread safe or not?

查看:107
本文介绍了如何确保静态类及其成员是否是线程安全的?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

//Controller
    public ActionResult AddMail(Guid userId)
    {
        EmailNotification.QueueMailAync(userId);
        .
        .
        //Some stuffs - QueueMailAync may call more time in a request.
        EmailNotification.QueueMailAync(userId);
        .
        .
    }

    //BL
    public static class EmailNotification
    {
    public static void QueueMailAync(Guid userId)
    {
        HostingEnvironment.QueueBackgroundWorkItem
        (
            cancellationToken =>
            {
                try
                {
                    QueueMail(userId);
                }
                catch (Exception e)
                {
                    logger.Error(e);
                }
            }
        );
    }

    static void QueueMail(Guid userId)
    {
        using (var context = new DBEntities())
        {
            var user = context.Users.FirstOrDefault(u => u.Id == userId);

            string body = context.EmailContents.FirstOrDefault().BodyText;
            body = body.Replace("{USER_NAME}",user.UserName);

            var mail = new ArchOver.Model.Email();
            mail.BodyText = body;
            mail.UserId = userId;
            mail.Subject = "Aync";
            mail.EmailTo = user.Person.Email;

            context.Emails.Add(mail);
            context.SaveChanges();
        }
    }
}





我尝试了什么:



我是并行编程概念的新手。我正在尝试在我的项目中实现fire-and-forgot类方法。有人请评估上面的代码&请告诉我以上是否是线程安全的。



先谢谢。



What I have tried:

I'm new to parallel programming concepts. I'm trying to implement fire-and-forgot kind of method in my project. Somebody please evaluate the above code & let me whether the above is thread safe or not.

Thanks in Advance.

推荐答案

取决于关于你如何使用它。



更新:下一段错误。这是一个静态类。我会把它留在这里以获得优势

这里,你没有静态类,你有一个类的静态实例。不同之处在于您仍需要初始化它。最好的方法是使用延迟初始化 [ ^ ]。这是线程安全初始化的简便方法。



如果该类是stuct,那么您不必过于担心访问参数,但在任何一种情况下,最好是安全而不是抱歉。



锁定封装可以防止多个线程一次进入代码。



Lock的写法如下:



更新:锁用于避免线程互相帮助。以下示例仅是锁定如何工作的示例。

It depends on how you use it.

UPDATE: This next paragraph is wrong. It is a static class. I'll leave it here for posperity
Here, you don't have a static class, you have a static instance of a class. The difference is that you still need to initialize it. The best way is to use "Lazy Initialization[^]". This is a shorthand way of thread-safe initialization.

If the class is a "stuct" then you don't have to worry too much about access to the parameters, but in either case it's better to be safe than sorry.

A "Lock" encapsulation prevents more than one thread entering the code at any one time.

The Lock is written like so:

UPDATE: Locks are used to avoid threads getting in each others way. The below example is an example only of how locks work.
//The "key" object.  It can be any object but any lock with the same key can only be entered by one thread at a time.
var lockObj= new object();

public static int _prop;
public static int prop{
  get{
    Lock(lockObj){
      return _prop;
    }
  }
  set{
    Lock(lockObj){
      _prop = value;
    }
  }
}





getter和setter都有相同密钥的锁。如果一个线程进入任何一个线程,那么任何其他线程都必须等待第一个线程退出锁定才能进入。



这是手动线程的基础知识 - 安全。还有其他一些事情要记住,如线程加入,等待等。谷歌搜索应突出细微差别。



希望有所帮助^ _ ^

Andy



The getter and setter both have locks with the same key. If a thread enters either one then any other thread will have to wait for the first thread to exit the lock before it can enter.

That's the basics of manual thread-safety. There are other things to keep in mind such as Thread Join, Wait etc. A google search should highlight the nuances.

Hope that helps ^_^
Andy


线程可以同时访问相同的资源(资源可以像变量一样简单),线程安全是一个潜在的问题。



我认为你显示的代码是线程安全的。多个线程可以同时使用的资源是数据库和日志记录输出。您创建一个本地DbContext并从数据库中只读取一次,然后编写一次,但编写一个新实体而不是更新现有实体,因此数据库锁定不会出现问题。并且日志代码应该是线程安全的设计。



所以不应该有任何锁定。
Thread safety is a potential issue whenever threads may access the same resources simultaneously (where a resource can be as simple as a variable).

I would assume your shown code is thread safe. The resources that could be used simultaneously by multiple threads are your database and the logging-output. You create a local DbContext and read only once from the database and then write once, but writing a new entity and not updating an existing one, so there can't be issues with database locks. And the logging code should be thread safe by design.

So there shouldn't be any locks required.


您可能需要使用锁定,这是一个示例:



You might need to use locking, here is an example:

private static readonly object SyncObject = new object(); 
 
public static void Log(string logMessage, TextWriter w)    { 
   // only one thread can own this lock, so other threads 
   // entering this method will wait here until lock is available. 
   lock(SyncObject) { 
      w.WriteLine("{0} {1}", DateTime.Now.ToLongTimeString(), 
          DateTime.Now.ToLongDateString()); 
      w.WriteLine("  :"); 
      w.WriteLine("  :{0}", logMessage); 
      w.WriteLine("-------------------------------"); 
      // Update the underlying file. 
      w.Flush(); 
   } 
} 


这篇关于如何确保静态类及其成员是否是线程安全的?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆