使用互斥锁来控制线程和计时器已用事件

时间:2016-10-11 11:27:42

标签: .net vb.net multithreading timer

在组件中,我需要通过UDP接收数据,而我的应用程序必须负责,所以我在这个组件类中创建了一个用于UDP监听的线程。收到数据时,必须有两个操作,延迟时间为20毫秒。在行动1之后必须始终遵循行动2.

所以我创建了一个Timer和一个互斥实例。收到数据后,互斥锁被锁定,因此无法执行操作1,而操作2则无法执行。在计时器结束后,将调用事件处理程序,其中处理第二个操作并释放互斥锁。这是理论上的计划。

但是当我尝试释放它时,我得到一个错误,即互斥锁没有被锁定。

Imports System.Timers

Public Class CriticalActionProcessor
    Private mTimer As System.Timers.Timer
    Private mTimerMutex As Threading.Mutex

    Private mReceiveThread As Threading.Thread

    Public Sub New()
        ' do some initalizing

        mReceiveThread = New Threading.Thread(AddressOf ProcessUDP)
        mReceiveThread.IsBackground = True
        mReceiveThread.Start()

        mTimer = new Timer()
        mTimerMutex = New Threading.Mutex()
        AddHandler mTimer.Elapsed, Sub()
                                        ' do some things, that must happen after some time
                                        mTimerMutex.ReleaseMutex() ' here it throws an exception 
                                                                   ' because mutex is not locked
                                   End Sub
    End Sub

    Private Sub ProcessUDP
        Dim udpReceiver = New UdpClient(5668)
        Dim ipEndPoint = New IPEndPoint(IPAddress.Any, 5668)

        While (True)
            Dim receivedData As Byte() = udpReceiver.Receive(ipEndPoint)
            ' check received data
            mTimerMutex.WaitOne()
            Fire()
        End While
    End Sub

    Private Sub Fire()  
        ' do some things and after that start timer
        mTimer.Interval = 20
        mTimer.Start()
    End Sub
End Class

似乎UDP线程和计时器线程不共享互斥锁。如何防止在调用计时器经过处理程序之前第二次调用Fire()方法?

1 个答案:

答案 0 :(得分:0)

问题

这里的主要问题是您对Mutex如何工作的误解。 Mutex是一个锁,一旦被占用,只能由接受它的线程释放。

考虑一下洗手间的锁。如果约翰进入那里并锁定自己做他的东西,那么阿诺德就无法取消锁定......

这就是你在这里做的,一个线程(ProcessUDP)接受锁定,而计时器(在另一个线程上)试图释放它...

解决方案

我的第一个猜测是在调用Timer之前调用你的第一个动作,然后在sub中为你的定时器调用你的第二个动作:

'In the sub new, this is actually the second action
AddHandler mTimer.Elapsed, Sub() 
                                 'Do your second action here, 
                                 'since it will be called after the timer is done
                           End Sub

'This would be the first action
Private Sub Fire()  
    'Do your first action and after that start timer
    mTimer.Interval = 20
    mTimer.Start()
End Sub

这样你就不用担心互斥锁和锁定了。