Как определить многопоточное использование?
Достаточно ли сравнивать ManagedThreadId
во время создания объекта и во время вызова метода для проверки того, что он не используется в сценарии многопоточности?
public class SingleThreadSafe
{
private readonly int threadId;
public SingleThreadSafe()
{
threadId = Thread.CurrentThread.ManagedThreadId;
}
public void DoSomethingUsefulButNotThreadSafe()
{
if(threadId!=Thread.CurrentThread.ManagedThreadId)
{
throw new InvalidOperationException(
"This object is being accessed by a thread different than the one that created it. " +
" But no effort has been made to make this object thread safe.");
}
//Do something useful, like use a previously established DbConnection
}
}
Моя интуиция часто ошибается в потоковом режиме, поэтому я хотел проверить, есть ли крайние случаи, о которых я должен помнить.
Ответы
Ответ 1
Нет, этого недостаточно.
Идентификатор управляемого потока может повторно использоваться CLR, поэтому if(threadId!=Thread.CurrentThread.ManagedThreadId)
может возвращать false
, даже если вызывающий поток отличается от того, который используется для построения объекта.
То, что вы пытаетесь достичь, возможно путем сравнения ссылок:
if (!object.ReferenceEquals(Thread.CurrentThread, ThreadThatCreatedThis))
// ...
ИЗМЕНИТЬ:
MSDN говорит, однако, что:
Значение свойства ManagedThreadId не изменяется со временем, даже если неуправляемый код, на котором размещается среда выполнения общего языка, реализует поток как волокно.
http://msdn.microsoft.com/en-us/library/system.threading.thread.managedthreadid%28v=vs.110%29.aspx
Ответ 2
Это в основном то, что делает Windows Forms. Вот фрагмент из Control.InvokeRequired
(цитируется из справочного источника ):
public bool InvokeRequired {
get {
using (new MultithreadSafeCallScope())
{
...
int hwndThread = SafeNativeMethods.GetWindowThreadProcessId(hwnd, out pid);
int currentThread = SafeNativeMethods.GetCurrentThreadId();
return(hwndThread != currentThread);
}
}
}
Если сравнивать идентификаторы потоков достаточно хорошо для Windows Forms, я полагаю, это было бы достаточно для меня...
Ответ 3
Я боюсь, что это не так.
В подобных сценариях я использую ThreadStatic (или Thread Локальное хранилище)