有效的方法来同步执行不同类中的代码的线程?

时间:2018-04-14 17:49:45

标签: .net vb.net multithreading winforms thread-safety

我只是想知道是否有可能以这种“实验性”方式管理Windows窗体进度条:

  • 我想在一个 WorkerClass 对象中执行代码的线程中从主窗体控制条形,该对象包含一个函数 doWork 来执行繁重的计算。
  • WorkerClass 包含两个由 doWork 函数更新的成员变量,这些变量可从表单访问以同步线程并保持已完成工作的跟踪。
  • 由于我需要为这些成员变量提供线程安全性,我在主窗体中构建了两个 synclocking 对象并将它们传递给 doWork 函数
  • doWork 函数返回一个主窗体所需的值,以便完成他的工作,所以我发现棘手的事实我必须告诉表单线程等到返回值。

    这是 WorkerClass 代码:

    Public Class WorkerClass
            Private mBarValue As Integer
            Private mStartNow As Boolean
    
            Public ReadOnly Property BarValue
                    Get
                            Return mBarValue
                    End Get
            End Property
    
            Public ReadOnly Property StartNow As Boolean
                    Get
                            Return mStartNow
                    End Get
            End Property
    
            Public Sub New()
                    mBarValue = 0
                    mStartNow = False
            End Sub
    
            Public Function doWork(ByRef list As ArrayList) As Integer
    
                    SyncLock (list.Item(0))
                            mStartNow = True
                    End SyncLock
    
                    'Do your work and update status
                    For i As Integer = 0 To 99
                            Thread.Sleep(10)
                            SyncLock (list.Item(1))
                                    mBarValue += 1
                            End SyncLock
                    Next
    
                    SyncLock (list.Item(0))
                            mStartNow = False
                    End SyncLock
    
                    Return 1000
    
            End Function
    
    End Class
    

这是主要的表单代码:

    Public Class Form1
        Private lock As Object
        Private lock2 As Object
        Private integerNeeded As Integer

        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            Me.lock = New Object()
            Me.lock2 = New Object()
            Dim wc As New WorkerClass()
            Dim wT As New Thread(AddressOf workerThread)

            Me.ProgressBar1.Value = 0
            Me.ProgressBar1.Show()

            wT.Start(wc)

            Dim canStart As Boolean = False

            While Not canStart
                SyncLock (lock)
                    canStart = wc.StartNow
                End SyncLock
            End While
            Debug.WriteLine("Start")

            'Bar updater
            Dim currentProgress As Integer = 0

            While canStart
                SyncLock (lock2)
                    currentProgress = wc.BarValue
                End SyncLock

                If currentProgress Mod Me.ProgressBar1.Step = 0 Then
                    Me.ProgressBar1.PerformStep()
                    Debug.WriteLine(Me.ProgressBar1.Value)
                End If

                SyncLock (lock)
                    canStart = wc.StartNow
                End SyncLock
            End While

            While wT.IsAlive 'Wait until the thread is done. Need to guarantee the value is returned
            End While

            Debug.WriteLine("End")
            Me.ProgressBar1.Hide()

            REM Rest of the code with integerNeeded here...

        End Sub

        Private Sub workerThread(wc As Object)
            Dim locks As New ArrayList()
            locks.Add(lock)
            locks.Add(lock2)
            integerNeeded = wc.doWork(locks)
        End Sub
    End Class

我的问题:这似乎有效,但我觉得它很慢,甚至我不太信任它,有没有更有效的方法来实现它?我搜索了一些示例,但是我找不到任何线程在不同的类中执行代码的情况。

非常感谢!

1 个答案:

答案 0 :(得分:0)

您应该使用.net提供的内置方法来进行AutoResetEvent和ManualResetEvent之类的同步。例如

ManualResetEvent在内存中维护一个布尔变量。当布尔变量为false时,它会阻塞所有线程,当布尔变量为true时,它会解除阻塞所有线程。  在Task Parallel Library的帮助下,在单独的线程中启动不同的任务,例如

        Task task = Task.Factory.StartNew(() =>
        {
            GetFoo();
        });

        Task.Factory.StartNew(() =>
        {
            ShowFoo();
        });

 //Have an instance of manual reset event 
        static ManualResetEvent manualResetEvent = new 
        ManualResetEvent(false);


  //Send first signal to get Foo then reset it to wait 
        manualResetEvent.Set();
        manualResetEvent.Reset();


  //It will wait until  manualResetEvent is Set again
        manualResetEvent.Set();

   Here is a great article that can help you understand the concepts of synchronization. 
    http://dotnetpattern.com/threading-manualresetevent