问题
I have a ASP.NET web application that allows end users to upload a file. Once the file is on the server, I spawn a thread to process the file. The thread is passed data regarding the specific operation (UserId, file path, various options, etc.). Most of the data is passed around via objects and method parameters but UserId needs to be available more globally so I put it in thread-local storage.
The thread is lengthy but it just processes the file and aborts. Is my use of the named data slot safe in this circumstance? If UserA uploads a file then UserB uploads a file while the first file is still processing, is it possible that the thread for UserA will also be delegated to handle UserB, thus producing a conflict for the named slot? (i.e. The slot gets overwritten with UserB's id and the rest of the operation of UserA's file is linked to the wrong 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
Note that I am not asking if the LocalNamedDataStore slots are thread-safe. By definition, I know that they are.
回答1:
In this case your use of thread local storage is safe. No two threads will ever share the same local storage (hence it's thread local). So there is no chance that two concurrent requests will stomp on the others data.
Couple of other comments though
- Do avoid the use of
Thread.Abort. It's a very dangerous operation and truthfully not needed here. The thread will end the statement afterwards. - A better approach would be to create a class which contains the background operation that has the
UserIdas a local field. Each request gets a new class instance. This is a much easier way to pass the data around to the background tasks
回答2:
This is a safe operation.
I have to say that I that JaredPars opinion that it would be better to create a class and store the userid in that class as a field is incomplete to say the least.
Where do you then store that object? Since it is created per request you have to store it somewhere. Do you couple the page with this functionality? I wouldn't. Do you store in the Context.Items collection? That is a possibility but what do you do with unit tests where you are trying to abstract the code away from ASP.Net so it will be more testable?
I have personally done a hybrid of the two approaches: I create a single class that will contain all of the data elements that are request specific then I cache that object in Thread Local Storage. This allows the code to run in unit test frameworks without having to mock the ASP.Net runtime environment.
Another important point is this: if you intend to use asynchronous patterns in ASP.Net you should be aware that TLS is not forward to new threads when switching the execution context to a new thread. It is truly "Thread local".
来源:https://stackoverflow.com/questions/8317203/is-using-thread-local-storage-safe-for-this-operation