2016-05-29 6 views
-3

Эта функция ниже претендует на расширение функции Thread.Sleep() (или Win32 Sleep/SleepEx), которая влияет только на вызывающий поток.Учитывая идентификатор потока или дескриптор потока, как я могу определить состояние потока?

В моем suspendFunc лямбда Я хотел бы убедиться, что поток действительно приостановлен, прежде чем звонить Thread.Sleep(TimeSpan).

Я искал related Win32 thread functions получить состояние потока от ручки потока или идентификатор потока, но я не нашел ничего подобного, ни я не могу найти структуру или перечисление, который определяет нить состояния (только managed one), поэтому я не нашел подсказки, чтобы начать делать это.

Как я мог это сделать ?.


(Примечание: P/Запускает не поставляются в общий код, я думаю, что они не являются необходимыми для понимания и только увеличит размер кода.)

C#:

public static void SleepThread(int threadId, TimeSpan timespan) 
{ 
    IntPtr hThread = default(IntPtr); 
    int win32Err = 0; 

    // Returns the previous suspend count for the thread. 
    Func<int> suspendFunc =() => 
    { 
     int suspendCount = 0; 
     Debug.WriteLine("Sleeping..."); 
     Thread.Sleep(timespan); 
     Debug.WriteLine("Resuming thread..."); 
     suspendCount = ResumeThread(hThread); 
     CloseHandle(hThread); 
     return suspendCount; 
    }; 

    hThread = OpenThread(ThreadAccessRights.SuspendResume | ThreadAccessRights.Terminate, true, threadId); 
    win32Err = Marshal.GetLastWin32Error(); 

    if ((hThread == IntPtr.Zero)) { 
     throw new Win32Exception(win32Err); 

    } else { 
     Debug.WriteLine("Pausing thread..."); 
     Task<int> suspendTask = Task.Factory.StartNew<int>(suspendFunc); 
     SuspendThread64(hThread); 

    } 

} 

//======================================================= 
//Service provided by Telerik (www.telerik.com) 
//======================================================= 

VB.NET:

Public Shared Sub SleepThread(ByVal threadId As Integer, ByVal timespan As TimeSpan) 

    Dim hThread As IntPtr 
    Dim win32Err As Integer 

    Dim suspendFunc As Func(Of Integer) = 
     Function() As Integer ' Returns the previous suspend count for the thread. 
      Dim suspendCount As Integer 
      Debug.WriteLine("Sleeping...") 
      Thread.Sleep(timespan) 
      Debug.WriteLine("Resuming thread...") 
      suspendCount = ResumeThread(hThread) 
      CloseHandle(hThread) 
      Return suspendCount 
     End Function 

    hThread = OpenThread(ThreadAccessRights.SuspendResume Or ThreadAccessRights.Terminate, True, threadId) 
    win32Err = Marshal.GetLastWin32Error() 

    If (hThread = IntPtr.Zero) Then 
     Throw New Win32Exception(win32Err) 

    Else 
     Debug.WriteLine("Pausing thread...") 
     Dim suspendTask As Task(Of Integer) = Task.Factory.StartNew(Of Integer)(suspendFunc) 
     SuspendThread64(hThread) 

    End If 

End Sub 
+2

Я предполагаю, что реализация потоков в .NET отслеживает эту информацию. Чем больше вопрос, почему вы повторно реализуете Thread.Sleep. Во-первых, само использование этой функции является признаком плохо разработанной программы. И, конечно, не что-то, что имеет смысл для * другой * нити, той, которой вы не владеете. Если вы хотите приостановить такой поток, вызовите функцию 'SuspendThread'. Но на самом деле, не надо, потому что приостановленный поток - плохая идея, если вы не пишете отладчик. В противном случае, тупиковый город. –

+0

Приостановка использования не принадлежащей нити не должна означать плохо разработанную программу, она очень полезна, лучше всего подходит и подходит только во множестве сценариев: один простой пример: если вы используете сторонний инструмент командной строки, который выполняет (скажем, FFMPEG, инструмент видео конвертера), и что вы завернули свои функциональные возможности в графическом интерфейсе на основе .NET, а затем вы хотите добавить функции Pause/Resume в свой графический интерфейс, SuspendThread/ResumeThread требуется, если нет, то как вы будете взаимодействовать с потоком внешнего приложения, чтобы делать такую ​​вещь ?. Понимаете, это имеет смысл. Спасибо за комментарий! – ElektroStudios

+4

Звучит неплохо, но это эпический провал, ожидающий своего появления. Что делать, если эта длинная задача многопоточная? Вы не можете просто приостановить один поток. И да, я думаю, вы могли бы приостановить * все * потоков FFMPEG, но затем вы вернетесь к использованию SuspendThread. Не нужно писать весь этот код, и нет необходимости в этом вопросе. –

ответ

3

Это самое близкое, что я могу получить.

Function GetThreadState(ProcId As Integer, ThreadId As Integer) As Threading.ThreadState 
    For Each Thr As Threading.Thread In Process.GetProcessById(ProcId).Threads 
     If Thr.ManagedThreadId = ThreadId Then Return Thr.ThreadState 
    Next 
    Throw New ArgumentOutOfRangeException("Thread not found.") 
End Function 
Смежные вопросы