Click here to show toolbars of the Web Online Help System: show toolbars |
'******************************************************************************* ' ' File name: MThread.vb ' Location: See Matrox Example Launcher in the MIL Control Center ' ' ' Synopsis: This program shows how to use threads in a MIL application and ' synchronize them with event. It creates 4 processing threads that ' are used to work in 4 different regions of a display buffer. ' ' Thread usage: ' - The main thread starts a processing thread in each of the 4 different ' quarters of a display buffer. The main thread then waits for a key to ' be pressed to stop them. ' - The top-left and bottom-left threads work in a loop, as follows: the ' top-left thread adds a constant to its buffer, then sends an event to ' the bottom-left thread. The bottom-left thread waits for the event ' from the top-left thread, rotates the top-left buffer image, then sends an ' event to the top-left thread to start a new loop. ' - The top-right and bottom-right threads work the same way as the ' top-left and bottom-left threads, except that the bottom-right thread ' performs an edge detection operation, rather than a rotation. ' ' Note : - Under MIL-Lite, the threads will do graphic annotations instead. ' - Comment out the MIL.MdispSelect() if you wish to avoid benchmarking ' the display update overhead on CPU usage and processing rate. ' ' Copyright (C) Matrox Electronic Systems Ltd., 1992-2016. ' All Rights Reserved ' '******************************************************************************* Imports Microsoft.VisualBasic Imports System Imports System.Collections.Generic Imports System.Text Imports System.Threading Imports System.Runtime.InteropServices Imports Matrox.MatroxImagingLibrary Namespace MThread Friend Class Program ' Local constants. Private Const IMAGE_FILE As String = MIL.M_IMAGE_PATH & "Bird.mim" Private Const IMAGE_WIDTH As Integer = 256 Private Const IMAGE_HEIGHT As Integer = 240 Private Const STRING_LENGTH_MAX As Integer = 40 Private Const STRING_POS_X As Integer = 10 Private Const STRING_POS_Y As Integer = 220 Private Const DRAW_RADIUS_NUMBER As Integer = 5 Private Const DRAW_RADIUS_STEP As Integer = 10 Private Const DRAW_CENTER_POSX As Integer = 196 Private Const DRAW_CENTER_POSY As Integer = 180 ' Thread parameters object. Public Class THREAD_PARAM Public Id As MIL_ID Public System As MIL_ID Public OrgImage As MIL_ID Public SrcImage As MIL_ID Public DstImage As MIL_ID Public DispImage As MIL_ID Public DispOffsetX As MIL_INT Public DispOffsetY As MIL_INT Public ReadyEvent As MIL_ID Public DoneEvent As MIL_ID Public NumberOfIteration As Integer Public Radius As Integer Public [Exit] As Integer Public LicenseModules As MIL_INT Public SlaveThreadParam As THREAD_PARAM End Class ' Main function: ' -------------- Shared Sub Main(ByVal args() As String) Dim MilApplication As MIL_ID = MIL.M_NULL ' Application identifier. Dim MilRemoteApplication As MIL_ID = MIL.M_NULL ' Remote Application identifier. Dim MilSystem As MIL_ID = MIL.M_NULL ' System identifier. Dim MilDisplay As MIL_ID = MIL.M_NULL ' Display identifier. Dim MilImage As MIL_ID = MIL.M_NULL ' Image buffer identifiers. Dim MilOrgImage As MIL_ID = MIL.M_NULL Dim TParTopLeft As New THREAD_PARAM() ' Parameters passed to top-left thread. Dim TParBotLeft As New THREAD_PARAM() ' Parameters passed to bottom-left thread. Dim TParTopRight As New THREAD_PARAM() ' Parameters passed to top-right thread. Dim TParBotRight As New THREAD_PARAM() ' Parameters passed to bottom-right thread. Dim Time As Double = 0.0 ' Timer variables. Dim FramesPerSecond As Double = 0.0 Dim LicenseModules As MIL_INT = 0 ' List of available MIL modules. ' Allocate defaults. MIL.MappAllocDefault(MIL.M_DEFAULT, MilApplication, MilSystem, MilDisplay, CType(MIL.M_NULL, IntPtr), CType(MIL.M_NULL, IntPtr)) ' Allocate and display the main image buffer. MIL.MbufAlloc2d(MilSystem, IMAGE_WIDTH * 2, IMAGE_HEIGHT * 2, 8 + MIL.M_UNSIGNED, MIL.M_IMAGE + MIL.M_PROC + MIL.M_DISP, MilImage) MIL.MbufClear(MilImage, 0) MIL.MdispSelect(MilDisplay, MilImage) MIL.MdispInquire(MilDisplay, MIL.M_SELECTED, TParTopLeft.DispImage) ' Allocate an image buffer to keep the original. MIL.MbufAlloc2d(MilSystem, IMAGE_WIDTH, IMAGE_HEIGHT, 8 + MIL.M_UNSIGNED, MIL.M_IMAGE + MIL.M_PROC, MilOrgImage) ' Allocate a processing buffer for each thread. MIL.MbufAlloc2d(MilSystem, IMAGE_WIDTH, IMAGE_HEIGHT, 8 + MIL.M_UNSIGNED, MIL.M_IMAGE + MIL.M_PROC, TParTopLeft.SrcImage) MIL.MbufAlloc2d(MilSystem, IMAGE_WIDTH, IMAGE_HEIGHT, 8 + MIL.M_UNSIGNED, MIL.M_IMAGE + MIL.M_PROC, TParBotLeft.DstImage) MIL.MbufAlloc2d(MilSystem, IMAGE_WIDTH, IMAGE_HEIGHT, 8 + MIL.M_UNSIGNED, MIL.M_IMAGE + MIL.M_PROC, TParTopRight.SrcImage) MIL.MbufAlloc2d(MilSystem, IMAGE_WIDTH, IMAGE_HEIGHT, 8 + MIL.M_UNSIGNED, MIL.M_IMAGE + MIL.M_PROC, TParBotRight.DstImage) ' Allocate synchronization events. MIL.MthrAlloc(MilSystem, MIL.M_EVENT, MIL.M_DEFAULT, MIL.M_NULL, MIL.M_NULL, TParTopLeft.DoneEvent) MIL.MthrAlloc(MilSystem, MIL.M_EVENT, MIL.M_DEFAULT, MIL.M_NULL, MIL.M_NULL, TParBotLeft.DoneEvent) MIL.MthrAlloc(MilSystem, MIL.M_EVENT, MIL.M_DEFAULT, MIL.M_NULL, MIL.M_NULL, TParTopRight.DoneEvent) MIL.MthrAlloc(MilSystem, MIL.M_EVENT, MIL.M_DEFAULT, MIL.M_NULL, MIL.M_NULL, TParBotRight.DoneEvent) ' Inquire MIL licenses. MIL.MsysInquire(MilSystem, MIL.M_OWNER_APPLICATION, MilRemoteApplication) MIL.MappInquire(MilRemoteApplication, MIL.M_LICENSE_MODULES, LicenseModules) ' Initialize remaining thread parameters. TParTopLeft.System = MilSystem TParTopLeft.OrgImage = MilOrgImage TParTopLeft.DstImage = TParTopLeft.SrcImage TParTopLeft.DispOffsetX = 0 TParTopLeft.DispOffsetY = 0 TParTopLeft.ReadyEvent = TParBotLeft.DoneEvent TParTopLeft.NumberOfIteration = 0 TParTopLeft.Radius = 0 TParTopLeft.Exit = 0 TParTopLeft.LicenseModules = LicenseModules TParTopLeft.SlaveThreadParam = TParBotLeft TParBotLeft.System = MilSystem TParBotLeft.OrgImage = 0 TParBotLeft.SrcImage = TParTopLeft.DstImage TParBotLeft.DispImage = TParTopLeft.DispImage TParBotLeft.DispOffsetX = 0 TParBotLeft.DispOffsetY = IMAGE_HEIGHT TParBotLeft.ReadyEvent = TParTopLeft.DoneEvent TParBotLeft.NumberOfIteration = 0 TParBotLeft.Radius = 0 TParBotLeft.Exit = 0 TParBotLeft.LicenseModules = LicenseModules TParBotLeft.SlaveThreadParam = Nothing TParTopRight.System = MilSystem TParTopRight.OrgImage = MilOrgImage TParTopRight.DstImage = TParTopRight.SrcImage TParTopRight.DispImage = TParTopLeft.DispImage TParTopRight.DispOffsetX = IMAGE_WIDTH TParTopRight.DispOffsetY = 0 TParTopRight.ReadyEvent = TParBotRight.DoneEvent TParTopRight.NumberOfIteration = 0 TParTopRight.Radius = 0 TParTopRight.Exit = 0 TParTopRight.LicenseModules = LicenseModules TParTopRight.SlaveThreadParam = TParBotRight TParBotRight.System = MilSystem TParBotRight.OrgImage = 0 TParBotRight.SrcImage = TParTopRight.DstImage TParBotRight.DispImage = TParTopLeft.DispImage TParBotRight.DispOffsetX = IMAGE_WIDTH TParBotRight.DispOffsetY = IMAGE_HEIGHT TParBotRight.ReadyEvent = TParTopRight.DoneEvent TParBotRight.NumberOfIteration = 0 TParBotRight.Radius = 0 TParBotRight.Exit = 0 TParBotRight.LicenseModules = LicenseModules TParBotRight.SlaveThreadParam = Nothing ' Initialize the original image to process. MIL.MbufLoad(IMAGE_FILE, MilOrgImage) ' Start the 4 threads. Dim TopThreadDelegate As New MIL_THREAD_FUNCTION_PTR(AddressOf TopThread) Dim BotLeftThreadDelegate As New MIL_THREAD_FUNCTION_PTR(AddressOf BotLeftThread) Dim BotRightThreadDelegate As New MIL_THREAD_FUNCTION_PTR(AddressOf BotRightThread) Dim TParTopLeftHandle As GCHandle = GCHandle.Alloc(TParTopLeft) Dim TParBotLeftHandle As GCHandle = GCHandle.Alloc(TParBotLeft) Dim TParTopRightHandle As GCHandle = GCHandle.Alloc(TParTopRight) Dim TParBotRightHandle As GCHandle = GCHandle.Alloc(TParBotRight) MIL.MthrAlloc(MilSystem, MIL.M_THREAD, MIL.M_DEFAULT, TopThreadDelegate, CType(TParTopLeftHandle, IntPtr), TParTopLeft.Id) MIL.MthrAlloc(MilSystem, MIL.M_THREAD, MIL.M_DEFAULT, BotLeftThreadDelegate, CType(TParBotLeftHandle, IntPtr), TParBotLeft.Id) MIL.MthrAlloc(MilSystem, MIL.M_THREAD, MIL.M_DEFAULT, TopThreadDelegate, CType(TParTopRightHandle, IntPtr), TParTopRight.Id) MIL.MthrAlloc(MilSystem, MIL.M_THREAD, MIL.M_DEFAULT, BotRightThreadDelegate, CType(TParBotRightHandle, IntPtr), TParBotRight.Id) ' Start the timer. MIL.MappTimer(MIL.M_DEFAULT, MIL.M_TIMER_RESET + MIL.M_SYNCHRONOUS, CType(MIL.M_NULL, IntPtr)) ' Set events to start operation of top-left and top-right threads. MIL.MthrControl(TParTopLeft.ReadyEvent, MIL.M_EVENT_SET, MIL.M_SIGNALED) MIL.MthrControl(TParTopRight.ReadyEvent, MIL.M_EVENT_SET, MIL.M_SIGNALED) ' Report that the threads are started and wait for a key press to stop them. Console.Write(Constants.vbLf + "MULTI-THREADING:" + Constants.vbLf) Console.Write("----------------" + Constants.vbLf + Constants.vbLf) Console.Write("4 threads running..." + Constants.vbLf) Console.Write("Press <Enter> to stop." + Constants.vbLf + Constants.vbLf) Console.ReadKey() ' Signal the threads to exit. TParTopLeft.Exit = 1 TParTopRight.Exit = 1 ' Wait for all threads to terminate. MIL.MthrWait(TParTopLeft.Id, MIL.M_THREAD_END_WAIT) MIL.MthrWait(TParBotLeft.Id, MIL.M_THREAD_END_WAIT) MIL.MthrWait(TParTopRight.Id, MIL.M_THREAD_END_WAIT) MIL.MthrWait(TParBotRight.Id, MIL.M_THREAD_END_WAIT) ' Stop the timer and calculate the number of frames per second processed. MIL.MappTimer(MIL.M_DEFAULT, MIL.M_TIMER_READ + MIL.M_SYNCHRONOUS, Time) FramesPerSecond = (TParTopLeft.NumberOfIteration + TParBotLeft.NumberOfIteration + TParTopRight.NumberOfIteration + TParBotRight.NumberOfIteration) / Time ' Print statistics. Console.Write("Top-left iterations done: {0,4}." + Constants.vbLf, TParTopLeft.NumberOfIteration) Console.Write("Bottom-left iterations done: {0,4}." + Constants.vbLf, TParBotLeft.NumberOfIteration) Console.Write("Top-right iterations done: {0,4}." + Constants.vbLf, TParTopRight.NumberOfIteration) Console.Write("Bottom-right iterations done: {0,4}." + Constants.vbLf + Constants.vbLf, TParBotRight.NumberOfIteration) Console.Write("Processing speed for the 4 threads: {0:0.0} Images/Sec." + Constants.vbLf + Constants.vbLf, FramesPerSecond) Console.Write("Press <Enter> to end." + Constants.vbLf + Constants.vbLf) Console.ReadKey() ' Free threads. MIL.MthrFree(TParTopLeft.Id) MIL.MthrFree(TParBotLeft.Id) MIL.MthrFree(TParTopRight.Id) MIL.MthrFree(TParBotRight.Id) ' Free events. MIL.MthrFree(TParTopLeft.DoneEvent) MIL.MthrFree(TParBotLeft.DoneEvent) MIL.MthrFree(TParTopRight.DoneEvent) MIL.MthrFree(TParBotRight.DoneEvent) ' Free buffers. MIL.MbufFree(TParTopLeft.SrcImage) MIL.MbufFree(TParTopRight.SrcImage) MIL.MbufFree(TParBotLeft.DstImage) MIL.MbufFree(TParBotRight.DstImage) MIL.MbufFree(MilOrgImage) MIL.MbufFree(MilImage) ' Free the GCHandles TParTopLeftHandle.Free() TParBotLeftHandle.Free() TParTopRightHandle.Free() TParBotRightHandle.Free() ' Free defaults. MIL.MappFreeDefault(MilApplication, MilSystem, MilDisplay, MIL.M_NULL, MIL.M_NULL) End Sub ' Top-left and top-right threads' function (Add an offset): ' --------------------------------------------------------- Private Shared Function TopThread(ByVal ThreadParameters As IntPtr) As UInteger Dim TPar As THREAD_PARAM = CType((CType(ThreadParameters, GCHandle)).Target, THREAD_PARAM) Do While TPar.Exit = 0 ' Wait for bottom ready event before proceeding. MIL.MthrWait(TPar.ReadyEvent, MIL.M_EVENT_WAIT) ' For better visual effect, reset SrcImage to the original image regularly. If (TPar.NumberOfIteration Mod 192) = 0 Then MIL.MbufCopy(TPar.OrgImage, TPar.SrcImage) End If If (TPar.LicenseModules And MIL.M_LICENSE_IM) <> 0 Then ' Add a constant to the image. MIL.MimArith(TPar.SrcImage, 1L, TPar.DstImage, MIL.M_ADD_CONST + MIL.M_SATURATION) Else ' Under MIL-Lite draw a variable size rectangle in the image. TPar.SlaveThreadParam.Radius = (TPar.NumberOfIteration Mod DRAW_RADIUS_NUMBER) * DRAW_RADIUS_STEP TPar.Radius = TPar.SlaveThreadParam.Radius MIL.MgraColor(MIL.M_DEFAULT, &HFF) MIL.MgraRectFill(MIL.M_DEFAULT, TPar.DstImage, DRAW_CENTER_POSX - TPar.Radius, DRAW_CENTER_POSY - TPar.Radius, DRAW_CENTER_POSX + TPar.Radius, DRAW_CENTER_POSY + TPar.Radius) End If ' Increment iteration count and draw text. TPar.NumberOfIteration += 1 MIL.MgraColor(MIL.M_DEFAULT, &HFF) MIL.MgraText(MIL.M_DEFAULT, TPar.DstImage, STRING_POS_X, STRING_POS_Y, String.Format("{0}", TPar.NumberOfIteration)) ' Update the display. If (TPar.DispImage <> MIL.M_NULL) Then MIL.MbufCopyColor2d(TPar.DstImage, TPar.DispImage, MIL.M_ALL_BANDS, 0, 0, MIL.M_ALL_BANDS, TPar.DispOffsetX, TPar.DispOffsetY, IMAGE_WIDTH, IMAGE_HEIGHT) End If ' Signal to the bottom thread that the first part of the processing is completed. MIL.MthrControl(TPar.DoneEvent, MIL.M_EVENT_SET, MIL.M_SIGNALED) Loop ' Require the bottom thread to exit. TPar.SlaveThreadParam.Exit = 1 ' Signal the bottom thread to wake up. MIL.MthrControl(TPar.DoneEvent, MIL.M_EVENT_SET, MIL.M_SIGNALED) ' Before exiting the thread, make sure that all the commands are executed. MIL.MthrWait(TPar.System, MIL.M_THREAD_WAIT, CType(MIL.M_NULL, IntPtr)) Return 1 End Function ' Bottom-left thread function (Rotate): ' ------------------------------------- Private Shared Function BotLeftThread(ByVal ThreadParameters As IntPtr) As UInteger Dim TPar As THREAD_PARAM = CType((CType(ThreadParameters, GCHandle)).Target, THREAD_PARAM) Dim Angle As Double = 0.0 Dim AngleIncrement As Double = 0.5 Do While TPar.Exit = 0 ' Wait for the event in top-left function to be ready before proceeding. MIL.MthrWait(TPar.ReadyEvent, MIL.M_EVENT_WAIT) If (TPar.LicenseModules And MIL.M_LICENSE_IM) <> 0 Then ' Rotate the image. MIL.MimRotate(TPar.SrcImage, TPar.DstImage, Angle, MIL.M_DEFAULT, MIL.M_DEFAULT, MIL.M_DEFAULT, MIL.M_DEFAULT, MIL.M_NEAREST_NEIGHBOR + MIL.M_OVERSCAN_CLEAR) Angle += AngleIncrement If (Angle >= 360) Then Angle -= 360 End If Else ' Under MIL-Lite copy the top-left image and draw ' a variable size filled circle in the image. */ MIL.MbufCopy(TPar.SrcImage, TPar.DstImage) MIL.MgraColor(MIL.M_DEFAULT, &H80) MIL.MgraArcFill(MIL.M_DEFAULT, TPar.DstImage, DRAW_CENTER_POSX, DRAW_CENTER_POSY, TPar.Radius, TPar.Radius, 0, 360) End If ' Increment iteration count and draw text. TPar.NumberOfIteration += 1 MIL.MgraColor(MIL.M_DEFAULT, &HFF) MIL.MgraText(MIL.M_DEFAULT, TPar.DstImage, STRING_POS_X, STRING_POS_Y, String.Format("{0}", TPar.NumberOfIteration)) ' Update the display. If (TPar.DispImage <> MIL.M_NULL) Then MIL.MbufCopyColor2d(TPar.DstImage, TPar.DispImage, MIL.M_ALL_BANDS, 0, 0, MIL.M_ALL_BANDS, TPar.DispOffsetX, TPar.DispOffsetY, IMAGE_WIDTH, IMAGE_HEIGHT) End If ' Signal to the top-left thread that the last part of the processing is completed. MIL.MthrControl(TPar.DoneEvent, MIL.M_EVENT_SET, MIL.M_SIGNALED) Loop ' Before exiting the thread, make sure that all the commands are executed. MIL.MthrWait(TPar.System, MIL.M_THREAD_WAIT, CType(MIL.M_NULL, IntPtr)) Return 1 End Function ' Bottom-right thread function (Edge Detect): ' ------------------------------------------- Private Shared Function BotRightThread(ByVal ThreadParameters As IntPtr) As UInteger Dim TPar As THREAD_PARAM = CType((CType(ThreadParameters, GCHandle)).Target, THREAD_PARAM) Do While TPar.Exit = 0 ' Wait for the event in top-right function to be ready before proceeding. MIL.MthrWait(TPar.ReadyEvent, MIL.M_EVENT_WAIT) If (TPar.LicenseModules And MIL.M_LICENSE_IM) <> 0 Then ' Perform an edge detection operation on the image. MIL.MimConvolve(TPar.SrcImage, TPar.DstImage, MIL.M_EDGE_DETECT_SOBEL_FAST) Else ' Under MIL-Lite copy the top-right image and draw ' a variable size filled circle in the image. MIL.MbufCopy(TPar.SrcImage, TPar.DstImage) MIL.MgraColor(MIL.M_DEFAULT, &H40) MIL.MgraArcFill(MIL.M_DEFAULT, TPar.DstImage, DRAW_CENTER_POSX, DRAW_CENTER_POSY, TPar.Radius / 2, TPar.Radius / 2, 0, 360) End If ' Increment iteration count and draw text. TPar.NumberOfIteration += 1 MIL.MgraColor(MIL.M_DEFAULT, &HFF) MIL.MgraText(MIL.M_DEFAULT, TPar.DstImage, STRING_POS_X, STRING_POS_Y, String.Format("{0}", TPar.NumberOfIteration)) ' Update the display. If (TPar.DispImage <> MIL.M_NULL) Then MIL.MbufCopyColor2d(TPar.DstImage, TPar.DispImage, MIL.M_ALL_BANDS, 0, 0, MIL.M_ALL_BANDS, TPar.DispOffsetX, TPar.DispOffsetY, IMAGE_WIDTH, IMAGE_HEIGHT) End If ' Signal to the top-right thread that the last part of the processing is completed. MIL.MthrControl(TPar.DoneEvent, MIL.M_EVENT_SET, MIL.M_SIGNALED) Loop ' Before exiting the thread, make sure that all the commands are executed. MIL.MthrWait(TPar.System, MIL.M_THREAD_WAIT, CType(MIL.M_NULL, IntPtr)) Return 1 End Function End Class End Namespace