Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get a thread handle to pass to CancelSynchronousIO?

Creating a background thread in C# in the normal way -

Thread t = new Thread(....);
t.IsBackground = true;
t.Start();
etc etc

Wanting to call CancelSynchronousIO from the main thread to cancel a blocking IO call on the background thread. Don't know how to get a thread handle in the form of an IntPtr to pass to the function:

[DllImport("kernel32.dll", SetLastError=true)]
static extern bool CancelSynchronousIo(IntPtr threadHandle);

There seems to be various ways of getting a thread ID, but not a handle? And the ways of getting a thread ID seem to give you an ID only within the managed environment, so no use for PInvoke calls? I'm guessing I'm missing something.

Do I need to do other PInvoke calls to get the thread handle or is there an easier way?

like image 257
user3757455 Avatar asked Jul 02 '14 20:07

user3757455


1 Answers

You can do it, but it is highly not recommended.

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);
    }
}
like image 182
masaki Avatar answered Sep 20 '22 20:09

masaki