mirror of https://github.com/dahall/Vanara.git
152 lines
5.0 KiB
C#
152 lines
5.0 KiB
C#
using NUnit.Framework;
|
|
using System;
|
|
using System.Diagnostics;
|
|
using Vanara.Extensions;
|
|
using static Vanara.PInvoke.Kernel32;
|
|
|
|
namespace Vanara.PInvoke.Tests
|
|
{
|
|
[TestFixture]
|
|
public class ThreadPoolApiSetTests
|
|
{
|
|
[Test]
|
|
public void QuerySetThreadpoolStackInformationTest()
|
|
{
|
|
using (var pool = CreateThreadpool())
|
|
{
|
|
Assert.That(pool, ResultIs.ValidHandle);
|
|
Assert.That(QueryThreadpoolStackInformation(pool, out var si), ResultIs.Successful);
|
|
Assert.That(si.StackReserve.Value, Is.Not.Zero);
|
|
Assert.That(SetThreadpoolStackInformation(pool, si), ResultIs.Successful);
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void ThreadpoolIoWorkTimerTest()
|
|
{
|
|
InitializeThreadpoolEnvironment(out var CallBackEnviron);
|
|
|
|
// Create a custom, dedicated thread pool.
|
|
using (var pool = CreateThreadpool())
|
|
{
|
|
Assert.That(pool, ResultIs.ValidHandle);
|
|
|
|
// The thread pool is made persistent simply by setting both the minimum and maximum threads to 1.
|
|
SetThreadpoolThreadMaximum(pool, 1);
|
|
Assert.That(SetThreadpoolThreadMinimum(pool, 1), ResultIs.Successful);
|
|
|
|
// Create a cleanup group for this thread pool.
|
|
using (var cleanupgroup = CreateThreadpoolCleanupGroup())
|
|
{
|
|
Assert.That(cleanupgroup, ResultIs.ValidHandle);
|
|
cleanupgroup.AutoCloseMembers = true;
|
|
|
|
// Associate the callback environment with our thread pool.
|
|
CallBackEnviron.SetThreadpoolCallbackPool(pool);
|
|
|
|
// Associate the cleanup group with our thread pool. Objects created with the same callback environment as the cleanup
|
|
// group become members of the cleanup group.
|
|
CallBackEnviron.SetThreadpoolCallbackCleanupGroup(cleanupgroup, null);
|
|
|
|
// Create work with the callback environment.
|
|
var work = cleanupgroup.CreateWork(MyWorkCallback, default, CallBackEnviron);
|
|
Assert.That(work, ResultIs.ValidHandle);
|
|
|
|
// Submit the work to the pool. Because this was a pre-allocated work item (using CreateThreadpoolWork), it is guaranteed
|
|
// to execute.
|
|
SubmitThreadpoolWork(work);
|
|
|
|
// Create a timer with the same callback environment.
|
|
var timer = cleanupgroup.CreateTimer(MyTimerCallback, default, CallBackEnviron);
|
|
Assert.That(timer, ResultIs.ValidHandle);
|
|
|
|
// Set the timer to fire in one second.
|
|
var FileDueTime = TimeSpan.FromSeconds(-1).ToFileTimeStruct();
|
|
Assert.That(SetThreadpoolTimerEx(timer, FileDueTime, 0, 0), Is.False);
|
|
Assert.That(IsThreadpoolTimerSet(timer), Is.True);
|
|
|
|
using (var hFile = CreateFile(TestCaseSources.SmallFile, FileAccess.FILE_GENERIC_READ, System.IO.FileShare.Read, null, System.IO.FileMode.Open, FileFlagsAndAttributes.FILE_FLAG_OVERLAPPED))
|
|
using (var io = CreateThreadpoolIo(hFile, MyIoCallback, default, CallBackEnviron))
|
|
{
|
|
Assert.That(io, ResultIs.ValidHandle);
|
|
StartThreadpoolIo(io);
|
|
WaitForThreadpoolIoCallbacks(io, true);
|
|
}
|
|
|
|
// Delay for the timer to be fired
|
|
Sleep(1500);
|
|
}
|
|
}
|
|
|
|
void MyIoCallback(PTP_CALLBACK_INSTANCE Instance, IntPtr Context, IntPtr Overlapped, uint IoResult, UIntPtr NumberOfBytesTransferred, PTP_IO Io)
|
|
{
|
|
Debug.Write("MyIoCallback: I/O has fired.\n");
|
|
CancelThreadpoolIo(Io);
|
|
}
|
|
|
|
// Thread pool timer callback function template
|
|
void MyTimerCallback(PTP_CALLBACK_INSTANCE a, IntPtr b, PTP_TIMER c) => Debug.Write("MyTimerCallback: timer has fired.\n");
|
|
|
|
// This is the thread pool work callback function.
|
|
void MyWorkCallback(PTP_CALLBACK_INSTANCE a, IntPtr b, PTP_WORK c)
|
|
{
|
|
CallbackMayRunLong(a);
|
|
Debug.Write("MyWorkCallback: Task performed.\n");
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void ThreadpoolWaitTest()
|
|
{
|
|
SafeEventHandle retEvent;
|
|
// Create an auto-reset event.
|
|
using (var hEvent = CreateEvent(null, false, false, null))
|
|
using (retEvent = CreateEvent(null, false, false, null))
|
|
{
|
|
Assert.That(hEvent, ResultIs.ValidHandle);
|
|
|
|
using (var Wait = CreateThreadpoolWait(MyWaitCallback))
|
|
{
|
|
Assert.That(Wait, ResultIs.ValidHandle);
|
|
|
|
// Need to re-register the event with the wait object each time before signaling the event to trigger the wait callback.
|
|
for (var i = 0; i < 5; i++)
|
|
{
|
|
SetThreadpoolWait(Wait, hEvent);
|
|
|
|
SetEvent(hEvent);
|
|
|
|
// Delay for the waiter thread to act if necessary.
|
|
Sleep(500);
|
|
|
|
// Block here until the callback function is done executing.
|
|
WaitForThreadpoolWaitCallbacks(Wait, false);
|
|
|
|
// Ensure that callback return event is signaled.
|
|
WaitForSingleObject(retEvent, INFINITE);
|
|
}
|
|
|
|
SetThreadpoolWait(Wait);
|
|
}
|
|
}
|
|
|
|
// Thread pool wait callback function template
|
|
void MyWaitCallback(PTP_CALLBACK_INSTANCE a, IntPtr b, PTP_WAIT c, uint d)
|
|
{
|
|
Debug.Write("MyWaitCallback: wait is over.\n");
|
|
Sleep(200);
|
|
SetEventWhenCallbackReturns(a, retEvent);
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void TrySubmitThreadpoolCallbackTest()
|
|
{
|
|
Assert.That(TrySubmitThreadpoolCallback((i, c) =>
|
|
{
|
|
Debug.WriteLine("SimpleCallback from TrySubmitThreadpoolCallback");
|
|
DisassociateCurrentThreadFromCallback(i);
|
|
}), Is.True); ;
|
|
}
|
|
}
|
|
} |