>1
AbortではThreadAbortExceptionで適切な終了処理を行ってリークしないようにすることと、要求タイミングによってはキャッチができないことに対処ができるのであれば、Abortしてもかまわないです。
ですが、正しく処理できるかは、ネイティブ側をどのように呼んでいるか、ネイティブ側で何をやっているのかに依存するので、絶対的に正しいとは言えません。
ですから一般論として正しいと保証できないのでAbortは使うなとしか言えなくなります。
ゆえに、Abortしても問題がないかを判断できるのはあなただけであり、保証しなければならないのもあなたです。
ライブラリの作成もあなたが行っているのであれば、途中キャンセル可能なようにライブラリを改修するのが最善でしょう。
>2
CancellationTokenは高機能なフラグなので、IsCancellationRequestedをチェックするだけならBooleanをフラグとすることとたいして違いはないです。
その使い方だけならスレッド内の進捗ごとにフラグチェックして処理を抜けるだけになります。
そうではなく、CancellationTokenをイベントの発生源として扱うことで、キャンセル要求時にネイティブ側にたいしてにキャンセル処理を実行させる使い方ができます。
Imports System
Imports System.Threading
Module Module1
Sub Main()
Test1()
Console.WriteLine("-------------")
Test2()
Console.WriteLine("-------------")
Test3()
Console.WriteLine("終了")
Console.ReadKey()
End Sub
Private Sub WriteLine(msg As String)
Console.WriteLine(DateTime.Now.ToString("HH:mm:ss.fff") + " " + msg)
End Sub
'---------------------------------------------------------------------
Private Sub Test1()
WriteLine("Test1")
Dim th1 As System.Threading.Thread = New Thread(AddressOf p1)
th1.Start(Nothing)
System.Threading.Thread.Sleep(1000)
WriteLine("Request Abort")
th1.Abort()
th1.Join()
WriteLine(th1.ThreadState.ToString())
End Sub
Private Sub p1(ByVal o As Object)
WriteLine("CppFunc1 Start")
Try
CppFunc1()
Catch ex As System.Threading.ThreadAbortException
WriteLine("CppFunc1 Abort")
'Abortされたら安全に終了させる処理を実行しなければならない
'しなかったらメモリリークなどが起きる可能性がある
Finally
WriteLine("CppFunc1 Finally")
End Try
WriteLine("CppFunc1 End") 'Abortされると実行されない
End Sub
Private Sub CppFunc1()
System.Threading.Thread.Sleep(1000000) '途中解除する方法がないのでAbortするしかない
End Sub
'---------------------------------------------------------------------
Private Sub Test2()
WriteLine("Test2")
Dim th1 As System.Threading.Thread = New Thread(AddressOf p2)
th1.Start(System.Threading.CancellationToken.None)
System.Threading.Thread.Sleep(1000)
WriteLine("Request Abort")
th1.Abort() 'キャンセルせずにAbortしてもすぐには返ってこない
th1.Join()
WriteLine(th1.ThreadState.ToString())
End Sub
'---------------------------------------------------------------------
Private Sub Test3()
WriteLine("Test3")
'CancellationTokenをつかう
Dim tcs As New System.Threading.CancellationTokenSource()
Dim th2 As System.Threading.Thread = New Thread(AddressOf p2)
th2.Start(tcs.Token)
System.Threading.Thread.Sleep(1000)
WriteLine("Request Cancel")
tcs.Cancel()
th2.Join()
WriteLine(th2.ThreadState.ToString())
End Sub
Private Sub p2(ByVal o As Object)
Dim token As System.Threading.CancellationToken = CType(o, System.Threading.CancellationToken)
If token.IsCancellationRequested Then
Return
End If
WriteLine("CppFunc2 Start")
Try
Using ev As New System.Threading.ManualResetEvent(False)
Using reg = token.Register(New Action(Sub() 'tokenがキャンセルになったら呼び出される関数を登録
WriteLine("CppFunc2 Cancel")
ev.Set()
End Sub))
Using waitHandle As Microsoft.Win32.SafeHandles.SafeWaitHandle = ev.SafeWaitHandle()
Dim handle As IntPtr = waitHandle.DangerousGetHandle()
If token.IsCancellationRequested Then
Return
End If
CppFunc2(handle) '中止を通知するためのイベントハンドルをC++側に渡す
If token.IsCancellationRequested Then
Return
End If
CppFunc2(handle) '中止を通知するためのイベントハンドルをC++側に渡す
End Using 'waitHandle
End Using 'reg
End Using 'ev
Catch ex As System.Threading.ThreadAbortException
WriteLine("CppFunc2 Abort")
Catch
WriteLine("CppFunc2 Error")
Finally
WriteLine("CppFunc2 Finally")
End Try
WriteLine("CppFunc2 End")
End Sub
Private Sub CppFunc2(waithandle As IntPtr)
'例としてWin32 APIのWaitForSingleObject
WaitForSingleObject(waithandle, 10000) 'WaitHandleがSetされたら時間前でも解除される
End Sub
<Runtime.InteropServices.DllImport("kernel32.dll", SetLastError:=True)>
Private Function WaitForSingleObject(handle As IntPtr, dwMilliseconds As Integer) As Integer
End Function
End Module