#c# #multithreading
#c# #многопоточность
Вопрос:
Создание фонового потока в C # обычным способом —
Thread t = new Thread(....);
t.IsBackground = true;
t.Start();
etc etc
Хочу вызвать CancelSynchronousIO
из основного потока, чтобы отменить блокирующий вызов ввода-вывода в фоновом потоке. Не знаю, как получить дескриптор потока в форме IntPtr для передачи функции:
[DllImport("kernel32.dll", SetLastError=true)]
static extern bool CancelSynchronousIo(IntPtr threadHandle);
Кажется, существуют различные способы получения идентификатора потока, но не дескриптора? И способы получения идентификатора потока, похоже, дают вам идентификатор только в управляемой среде, так что нет смысла в вызовах PInvoke? Я предполагаю, что я что-то упускаю.
Нужно ли мне выполнять другие вызовы PInvoke, чтобы получить дескриптор потока, или есть более простой способ?
Комментарии:
1. ваш код может выполняться в управляемом потоке, а не в собственном потоке.
2. смотрите: msdn.microsoft.com/en-us/library/74169f59 (v = против 110).aspx
3. @DanielA. Белый: Управляемые потоки являются собственными потоками; Волокна почти никогда не используются.
4. @SLaks но его можно перенести в другое место: «Идентификатор потока операционной системы не имеет фиксированной связи с управляемым потоком, потому что неуправляемый хост может контролировать связь между управляемыми и неуправляемыми потоками. В частности, сложный хост может использовать Fiber API для планирования множества управляемых потоков для одного потока операционной системы или для перемещения управляемого потока между различными потоками операционной системы.»
5. Да, но никто этого не делает.
Ответ №1:
Вы можете это сделать, но это настоятельно не рекомендуется.
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading;
class Program
{
[DllImport("kernel32.dll", SetLastError = true)]
static extern uint GetCurrentThreadId();
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr OpenThread(uint desiredAccess, bool inheritHandle, uint threadId);
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool CloseHandle(IntPtr handle);
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool CancelSynchronousIo(IntPtr threadHandle);
static bool CancelSynchronousIo(uint threadId)
{
// GENERIC_WRITE, Non-inheritable
var threadHandle = OpenThread(0x40000000, false, (uint)threadId);
var ret = CancelSynchronousIo(threadHandle);
CloseHandle(threadHandle);
return ret;
}
static void Main(string[] args)
{
uint threadId = 0;
using (var threadStarted = new AutoResetEvent(false))
{
var thread = new Thread(() =>
{
try
{
Thread.BeginThreadAffinity();
threadId = GetCurrentThreadId();
threadStarted.Set();
// will throws System.OperationCanceledException
Console.ReadLine();
}
finally
{
Thread.EndThreadAffinity();
}
});
thread.Start();
threadStarted.WaitOne();
}
Debugger.Break();
CancelSynchronousIo(threadId);
}
}
Комментарии:
1. Можете ли вы объяснить или сослаться, почему это не рекомендуется?
2. Я считаю, что вам нужно добавить
[return: MarshalAs(UnmanagedType.Bool)]
вCancelSynchronousIo
. Смотрите здесь .3. Кроме того, документально подтверждено, что вам нужно
THREAD_TERMINATE
право доступа. Я не думаю, что вы можете использовать0x40000000
сOpenThread
.