Исполнение застряло на ManualResetEvent.Set после приостановки другого потокаC#

Место общения программистов C#
Ответить
Anonymous
 Исполнение застряло на ManualResetEvent.Set после приостановки другого потока

Сообщение Anonymous »

Я создал инструмент, который находит и возобновляет подвесные потоки конкретного процесса (причина этого инструмента не имеет значения). Чтобы проверить инструмент, я создал следующий модульный тест: < /p>

Код: Выделить всё

// Arrange
var timeout = TimeSpan.FromSeconds(10);
var locker = new object();
var suspendEvent = new ManualResetEventSlim(false);
ulong threadId = 0;

var thread = new Thread(() =>
{
lock (locker)
{
threadId = InteropAPI.TRGetCurrentThreadId();
}

Log($"Thread started: {threadId}");
suspendEvent.Wait();
Log($"Thread finished: {threadId}");
});
thread.Start();

for (var i = 0; i < 100; i++)
{
lock (locker)
{
if (threadId != 0)
{
break;
}
}
Thread.Sleep(10);
}

Assert.That(threadId, Is.Not.EqualTo(0));

// Act
Log("Suspending thread...");
InteropAPI.TRSuspendThread(threadId);
Log("Thread suspended");
suspendEvent.Set();
Log("Event set");

// Assert part omitted
trgetCurrentThreadId просто вызовы winapi getCurrentThreadId, в то время как trsuspendthread вызовы SuprendThread.
Эта версия теста работает просто отлично, казнили тысячи раз. Вот немного более чистая версия, которая пытается избавиться от ThreadId Have Hack:

Код: Выделить всё

// Arrange
var timeout = TimeSpan.FromSeconds(10);
var locker = new object();
var suspendEvent = new ManualResetEventSlim(false);
var threadSetEvent = new ManualResetEventSlim(false);
ulong threadId = 0;

var thread = new Thread(() =>
{
lock (locker)
{
threadId = InteropAPI.TRGetCurrentThreadId();
}
threadSetEvent.Set();

Log($"Thread started: {threadId}");
suspendEvent.Wait();
Log($"Thread finished: {threadId}");
});
thread.Start();

threadSetEvent.Wait(timeout);
Assert.That(threadId, Is.Not.EqualTo(0));

// Act
Log("Suspending thread...");
InteropAPI.TRSuspendThread(threadId);
Log("Thread suspended");
suspendEvent.Set();
Log("Event set");
< /code>
Проблема с этой версией, она застряла. В частности, в вызове приостановтию .shipentevent.set () 
. Отпечатаны журналы: < /p>

Код: Выделить всё

Thread started: 37348
Suspending thread...
Thread suspended
< /code>
Поток приостанавливается, как и ожидалось, как подтверждено через процесс Explorer. Принудительно возобновление потока, используя процесс Explorer, делает тестовую отделку и распечатайте остальные журналы: < /p>
Event set
Thread finished: 37348
Первоначально, я думал, что, возможно, время выполнения перемещает управляемый, контрольный тестовый поток, в подвесную систему потока, однако печатает TrgetCurrentThreadId в основном потоке. . < /p>
Стек нативного вызовов для тестового потока, во время тупика, кажется: < /p>

Код: Выделить всё

ntdll.dll!NtWaitForAlertByThreadId+0x14
ntdll.dll!TpWorkOnBehalfClearTicket+0x2c3
ntdll.dll!RtlEnterCriticalSection+0x254
ntdll.dll!RtlEnterCriticalSection+0x42
< /code>
стек подвесного потока: < /p>
ntdll.dll!ZwCreateEvent+0x14
KERNELBASE.dll!CreateEventW+0x95
< /code>

[*] Почему выполнение останавливается на suppustevent.set () < /code>? Требует ли вызов set () 
, который не находился в приостановленном состоянии или иным образом он может тупиться? 't? Это просто из -за тонкой разницы в времени, которая мешает расе? > Тесты никогда не выполняются параллельно
[*] Этот тест был выполнен в Entine Engine, в которой используется пользовательская версия Mono


Подробнее здесь: https://stackoverflow.com/questions/793 ... her-thread
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C#»