使用线程本地存储安全吗?

时间:2011-11-29 20:21:32

标签: asp.net vb.net multithreading threadpool

我有一个ASP.NET Web应用程序,允许最终用户上传文件。一旦文件在服务器上,我就会生成一个线程来处理该文件。线程传递有关特定操作(UserId,文件路径,各种选项等)的数据。大多数数据是通过对象和方法参数传递的,但UserId需要更全局可用,因此我将其放在线程本地存储中。

线程很长但它只处理文件并中止。在这种情况下,我对命名数据槽的使用是否安全? 如果UserA上传文件,那么UserB在第一个文件仍在处理时上传文件,是否可能会委托UserA的线程处理UserB,从而产生指定插槽的冲突? (即插槽被UserB的id覆盖,UserA文件的其余操作链接到错误的User,UserB)。

Public Class FileUploadProcess
    Public UserId as String

    Public Sub ExecuteAsync()
        Dim t As New Thread(New ThreadStart(AddressOf ProcessFile))
        t.Start()
    End Sub

    Protected Sub ProcessFile()
        Dim slot As LocalDataStoreSlot = Thread.GetNamedDataSlot("UserId")
        Thread.SetData(slot, UserId)

        'lengthy operation to process file

        Thread.FreeNamedDataSlot("UserId")
        Thread.CurrentThread.Abort()
    End Sub
End Class

注意我不是在问LocalNamedDataStore个插槽是否是线程安全的。根据定义,我知道它们是。

2 个答案:

答案 0 :(得分:5)

在这种情况下,您使用线程本地存储是安全的。没有两个线程将共享相同的本地存储(因此它的线程本地)。因此,两个并发请求不会踩踏其他数据。

其他一些评论虽然

  • 请避免使用Thread.Abort。这是一个非常危险的操作,在这里真的不需要。线程将在之后结束语句。
  • 更好的方法是创建一个包含UserId作为本地字段的后台操作的类。每个请求都会获得一个新的类实例。这是将数据传递给后台任务的更简单方法

答案 1 :(得分:2)

这是一项安全的操作。

我不得不说我认为JaredPars认为创建一个类并将该类中的userid存储为字段会更好,至少可以说是不完整的。

然后你在哪里存储该对象?由于它是根据请求创建的,因此您必须将其存储在某处。你是否将页面与此功能结合在一起?我不会。你存储在Context.Items集合中吗?这是一种可能性,但你如何处理单元测试,你试图从ASP.Net中抽象代码,以便它更可测试?

我亲自完成了两种方法的混合:我创建了一个包含所有特定于请求的数据元素的类,然后在线程本地存储中缓存该对象。这允许代码在单元测试框架中运行,而无需模拟ASP.Net运行时环境。

另一个重要的一点是:如果您打算在ASP.Net中使用异步模式,您应该知道在将执行上下文切换到新线程时,TLS不会转发到新线程。它真的是“本地线程”。