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

Posted

技术标签:

【中文标题】同步线程在不同类中执行代码的有效方法?【英文标题】:Efficient way to synchronize threads executing code in different classes? 【发布时间】:2018-09-24 20:14:12 【问题描述】:

我只是想知道是否可以以这种“实验性”的方式管理 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】:

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

ManualResetEvent 在内存中维护一个布尔变量。当布尔变量为假时,它会阻塞所有线程,当布尔变量为真时,它会解除对所有线程的阻塞。 例如,借助任务并行库在单独的线程中启动不同的任务

        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 

【讨论】:

以上是关于同步线程在不同类中执行代码的有效方法?的主要内容,如果未能解决你的问题,请参考以下文章

多线程中锁的释放问题

同步随笔

OkHttp 如何在不使用线程的情况下通过看似同步的 HTTP 连接执行并行 HTTP 请求?

Java多线程冲突解决——同步锁

线程同步与死锁

java多线程——锁机制synchronized(同步方法)