从进程内会话读/写对象是原子操作吗?

时间:2014-09-25 18:29:45

标签: asp.net asp.net-mvc

我正在单个请求中的不同线程中从会话中读取/写入对象,如下所示:

public class HomeController : Controller
{
    public int Index()
    {
        Task.WaitAll(DoStuff(), DoMoreStuff());
        var foo = Session["foo"] as Foo;
        return foo.MyProperty;
    }

    public Task DoStuff()
    {
        return Task.Factory.StartNew(() =>
        {
            var foo = Session["foo"] as Foo;
            if (foo == null || foo.MyProperty == 1)
                foo = new Foo { MyProperty = 1 };
            Session["foo"] = foo;
        });
    }

    public Task DoMoreStuff()
    {
        return Task.Factory.StartNew(() =>
        {
            var foo = Session["foo"] as Foo;
            if (foo == null || foo.MyProperty == 1)
                foo = new Foo { MyProperty = 2 };
            Session["foo"] = foo;
        });
    }
}

public class Foo
{
    public int MyProperty { get; set; }
}

现在这段代码中的逻辑显然没有意义,但是我提供它来显示我正在做的操作:

  • 阅读对象参考,
  • 编写对象引用,
  • 创建新对象
  • 阅读对象领域。

我没有修改现有的对象。这个代码一般可以破坏会话状态或内存吗?

这是具有默认进程内会话实现的ASP.NET MVC应用程序。

如果此代码可以破坏会话状态,我应该在每次访问此代码中的会话时锁定Session.SyncRoot吗?

1 个答案:

答案 0 :(得分:1)

读取和写入引用是原子的,但在这种情况下没有用,因为HttpSessionState类不是线程安全的。

如果一个线程在会话状态中设置了一个项目,而另一个线程同时获取或设置了一个项目,则HttpSessionState实例可能会被破坏。这会使它表现不正常或导致崩溃。

所以,是的,如果你想对来自不同线程的会话状态做任何事情,那么所有访问都需要在使用SyncRoot属性锁定的代码块中(或者如果你愿意,可以使用你自己的对象)这一点)。


HttpSessionState class的文档包含此标准声明:

  

"此类型的任何公共静态(在Visual Basic中为Shared)成员都是   线程安全。任何实例成员都不能保证是线程   。安全"

这意味着静态成员是线程安全的,因为他们没有做任何事情来专门破坏线程安全性,并且实例成员没有做任何事情来确保线程安全。它的设计根本不是线程安全的。