多线程(VFB教程3-3)

  勇芳 2018-2-17 2883

此处为VisualFreeBasic编程教程(从零开始学或VB进阶)的子章节部分,全部目录点链接。

使用多线程非常简单,就如同调用本地过程一样,可以启用任意个过程,必须是SUB

Dim 线程句柄 As Any Ptr = ThreadCreate(@线程过程, 参数)  '创建个线程,并且传递1个数字参数,只允许1个,必须是1个。

Threaddetach(线程句柄) '销毁句柄,只是句柄,不会停止和杀死线程,必须要销毁

Sub 线程过程(线程参数 As Integer) '只允许1个参数,而且必须是1个,是数字
  '这里线程要执行的代码,过程执行完,这线程就退出了
End Sub

调用和启动线程,平常使用时可以简化到一句

Threaddetach ThreadCreate(Cast(Any Ptr,@线程过程),参数) '经典调用方法

这里加个 Cast 语句是变量类型转换,可以避免编译器警告。可以说是必须要加个,当然不加也不会出错。

只能传一个参数,是有点不方便,但也可以传指针过去,实现多参数传递

Sub Myaaa() '
  Dim aa As Any Ptr = CAllocate(12) '申请内存,并清除内容全为 0
  '申请内存大小按参数来,自己算出多少,也可以大点,不能少,少了软件可能会崩溃
  CPtr(Long Ptr, aa)[0] = 111
  CPtr(Long Ptr, aa)[1] = 222
  CPtr(Long Ptr, aa)[2] = 333
  Threaddetach ThreadCreate(Cast(Any Ptr, @线程过程), aa) '经典调用方法
End Sub
Sub 线程过程(线程参数 As Any Ptr) '只允许1个参数,而且必须是1个,是数字
  '这里线程要执行的代码,过程执行完,这线程就退出了
  Print  CPtr(Long Ptr, 线程参数)[0],CPtr(Long Ptr, 线程参数)[1],CPtr(Long Ptr, 线程参数)[2] 
  
  Deallocate(线程参数) '释放内存
End Sub

要是遇到字符,可不能直接,可以自己算尺寸,我们可以用类来传,比较简单,方便

Type ABCabc
    aaa As Long 
    bbb As ZString *50 '必须是 zString ,不可以是 String 
    ccc As WString *10 
    eee As Double  
End Type  
Sub Myaaa() '
  Dim aa As ABCabc Ptr = CAllocate(1, SizeOf(ABCabc)) '申请内存,并清除内容全为 0
  '申请内存大小按参数来,自己算出多少,也可以大点,不能少,少了软件可能会崩溃
  aa->aaa = 100
  aa->bbb = "普通字符"
  aa->ccc = "宽字符"
  aa->eee = 123.123 
  Threaddetach ThreadCreate(Cast(Any Ptr, @线程过程), aa) '经典调用方法
End Sub
Sub 线程过程(aa As ABCabc Ptr) '只允许1个参数,而且必须是1个,是数字
  '这里线程要执行的代码,过程执行完,这线程就退出了
  Print aa->aaa, aa->bbb, aa->ccc, aa->eee  
  
  Deallocate(aa) '释放内存
End Sub


到这里结束吧,下面代码没测试,只是举例可以这么做,新手排除不了错误,误看。


下面等技术提高了再看吧,不建议新手处理。。

====================================================================================================================

只可以传1个参数给线程,线程句柄不用后,必须释放,就用 ThreadDetach ,只是释放句柄,但不会终止线程

有个 ThreadWait 是等待线程完成,才执行下一行,除非特殊情况,不然失去了多线程的意义,很少用到。

还有个种方法创建线程,可以带多个参数

''线程使用“ThreadCall”

Sub thread( id As String, tlock As Any Ptr, count As Integer )
    For i As Integer = 1 To count
        MutexLock tlock
        Print "线" & id;
        Locate , 20
        Print i & "/" & count
        MutexUnlock tlock
    Next
End Sub

Dim tlock As Any Ptr = MutexCreate()
Dim a As Any Ptr = ThreadCall thread("A", tlock, 6)
Dim b As Any Ptr = ThreadCall thread("B", tlock, 4)
ThreadWait a
ThreadWait b
MutexDestroy tlock
Print "全部完成(并且没有Dim Shared!)"

使用Threadcall是创建线程的更简单的方法,并允许将数据传递到线程,而不会有全局变量或不是类型安全的指针。但是,ThreadCreate更有效率,应该用于创建大量线程的程序。

Function IsThreadAlive(ByVal dwThread As HANDLE ) As BOOL  
'判断线程句柄是否被终止 , 如果终止返回FALSE,如果还活着返回TRUE 
    Dim bRet As BOOL ,ExitCode As Ulong 
        If GetExitCodeThread(dwThread,@ExitCode) Then
            If ExitCode = STILL_ACTIVE Then bRet = True
        End If
    Return bRet
End Function
’此函数已经在VFB函数库里,不需要自己创建,直接调用

有时需要知道,线程是不是活着还是终止,就用以上函数

Dim cc As HANDLE Ptr '线程指针
cc= ThreadCreate(@abc,0) '经典调用方法
If  IsThreadAlive(*cc) Then  '*CC 取出的是线程句柄
End If
Threaddetach cc '释放线程句柄
-------------------------------------------------
sub abc(aa as long)  '线程标准写法
.....
end sub

假如,有多个线程使用的全局变量,那么,就可能发生问题了,1个读1个写。

(如果是单个数字变量,可以不用考虑,字符串、数组等,肯定出问题)

MutexCreate创建个互斥体来,读写全局变量时用MutexLock锁定,过后用MutexUnlock解锁。

'使用Mutex进行线程同步的可视示例:
'“用户定义的线程”计算圆上的点坐标,
'和“主线程”绘制点数。
'
'如果你注释掉包含“MutexLock”和“MutexUnlock”的行
'(在“用户定义的线程”或/和“主线程”内),
'两个线程(“用户定义”和“主”)将不会同步,
'并且许多点不会在圆上绘制(由于非相干坐标)。

'-----------------------------------------------------------------------------------------------------

Type ThreadUDT                                   '通用用户线程UDT
    Dim handle As Any Ptr                        '任何用户线程的Ptr句柄
    Dim sync As Any Ptr                          '互斥体的任何Ptr句柄
    Dim quit As Byte                             '布尔到最终用户线程
    Declare Static Sub Thread (ByVal As Any Ptr) '通用用户线程程序
    Dim procedure As Sub (ByVal As Any Ptr)      '用户线程执行的过程(任何Ptr)
    Dim p As Any Ptr                             '任何Ptr传递给用户线程执行的过程
    Const false As Byte = 0                      '常数“假”
    Const true As Byte = Not False               '康斯坦丁“真”
End Type

Static Sub ThreadUDT.Thread (ByVal param As Any Ptr) '通用用户线程程序
    Dim tp As ThreadUDT Ptr = param                  '转换为通用用户线程UDT
    Do
        MutexLock(tp->sync)                          '互斥(锁定)用户线程
        tp->procedure(tp->p)                         '用户线程执行的过程(任何Ptr)
        MutexUnlock(tp->sync)                        'Mutex(解锁)用户线程
        Sleep 5
    Loop Until tp->quit = tp->true                   '测试结束用户线程
End Sub

'-----------------------------------------------------------------------------------------------------

Type Point2D
    Dim x As Integer
    Dim y As Integer
End Type

Const x0 As Integer = 640 / 2
Const y0 As Integer = 480 / 2
Const r0 As Integer = 200
Const pi As Single = 4 * Atn(1)

Sub PointOnCircle (ByVal p As Any Ptr)
    Dim pp As Point2D Ptr = p
    Dim teta As Single = 2 * pi * Rnd
    pp->x = x0 + r0 * Cos(teta)
    Sleep 5                            '增加不相关的数据发生的可能性
    pp->y = y0 + r0 * Sin(teta)
End Sub


Screen 12
Locate 30, 2
Print "<any_key >:exit";

Dim Pptr As Point2D Ptr = New Point2D
Pptr->x = x0 + r0 * Cos(0)
pptr->y = y0 + r0 * Sin(0)

Dim Tptr As ThreadUDT Ptr = New ThreadUDT
Tptr->sync = MutexCreate
Tptr->procedure = @PointOnCircle
Tptr->p = Pptr
Tptr->handle = ThreadCreate(@ThreadUDT.Thread, Tptr)

Do
    MutexLock(Tptr->sync)   '用于主线程的互斥(锁定)
    PSet (Pptr->x, Pptr->y)
    MutexUnlock(Tptr->sync) 'Mutex(解锁)主线程
    Sleep 5
Loop Until Inkey <> ""
 
Tptr->quit = Tptr->true
ThreadWait(Tptr->handle)
MutexDestroy(Tptr->sync)
Delete Tptr
Delete Pptr

非有必要,多个线程还是不要用全局变量为好,因为那样,老是在互相等待中,失去了多线程的同时运行的意义。

最新回复 (0)
返回
联系勇芳