예제 #1
0
        /// <summary>
        /// Entry point.
        /// </summary>
        public static void Main()
        {
            var threadExitCallbackDelegatePtr = Marshal.GetFunctionPointerForDelegate(ThreadExitCallbackDelegate);
            var callbackId = UnmanagedThread.SetThreadExitCallback(threadExitCallbackDelegatePtr);

            for (var i = 1; i <= ThreadCount; i++)
            {
                var threadLocalVal = i;

                var thread = new Thread(_ =>
                {
                    Console.WriteLine($"Managed thread #{threadLocalVal} started.");
                    UnmanagedThread.EnableCurrentThreadExitEvent(callbackId, new IntPtr(threadLocalVal));
                    Thread.Sleep(100);
                    Console.WriteLine($"Managed thread #{threadLocalVal} ended.");
                });

                thread.Start();
            }

            UnmanagedThreadsExitEvent.Wait();
            Console.WriteLine("All unmanaged threads have exited.");

            UnmanagedThread.RemoveThreadExitCallback(callbackId);
        }
예제 #2
0
        public void TestInvalidCallbackIdThrowsException()
        {
            Assert.Throws <InvalidOperationException>(() =>
                                                      UnmanagedThread.EnableCurrentThreadExitEvent(int.MaxValue, new IntPtr(1)));

            Assert.Throws <InvalidOperationException>(() =>
                                                      UnmanagedThread.RemoveThreadExitCallback(int.MaxValue));
        }
예제 #3
0
        public void TestThreadExitFiresWhenEnabled([Values(true, false)] bool enableThreadExitCallback)
        {
            using (var evt = new ManualResetEventSlim())
            {
                var threadLocalVal       = new IntPtr(42);
                var resultThreadLocalVal = IntPtr.Zero;

                UnmanagedThread.ThreadExitCallback callback = val =>
                {
                    // ReSharper disable once AccessToDisposedClosure
                    evt.Set();
                    resultThreadLocalVal = val;
                };

                GC.KeepAlive(callback);
                var callbackId = UnmanagedThread.SetThreadExitCallback(Marshal.GetFunctionPointerForDelegate(callback));

                try
                {
                    ParameterizedThreadStart threadStart = _ =>
                    {
                        if (enableThreadExitCallback)
                        {
                            UnmanagedThread.EnableCurrentThreadExitEvent(callbackId, threadLocalVal);
                        }
                    };

                    var t = new Thread(threadStart);

                    t.Start();
                    t.Join();

                    var threadExitCallbackCalled = evt.Wait(TimeSpan.FromSeconds(1));

                    Assert.AreEqual(enableThreadExitCallback, threadExitCallbackCalled);
                    Assert.AreEqual(enableThreadExitCallback ? threadLocalVal : IntPtr.Zero, resultThreadLocalVal);
                }
                finally
                {
                    UnmanagedThread.RemoveThreadExitCallback(callbackId);
                }
            }
        }