Returning a value from thread?

前端 未结 17 2530
不思量自难忘°
不思量自难忘° 2020-11-27 09:45

How do I return a value from a thread?

17条回答
  •  青春惊慌失措
    2020-11-27 10:32

    The BackgroundWorker is nice when developing for Windows Forms.

    Say you wanted to pass a simple class back and forth:

    class Anything {
        // Number and Text are for instructional purposes only
        public int Number { get; set; }
        public string Text { get; set; }
        // Data can be any object - even another class
        public object Data { get; set; }
    }
    

    I wrote up a short class that does the following:

    • Create or Clear a list
    • Start a loop
    • In loop, create a new item for the list
    • In loop, create a thread
    • In loop, send the item as a parameter to the thread
    • In loop, start the thread
    • In loop, add thread to list to watch
    • After loop, join each thread
    • After all joins have completed, display the results

    From inside the thread routine:

    • Call lock so that only 1 thread can enter this routine at a time (others have to wait)
    • Post information about the item.
    • Modify the item.
    • When the thread completes, the data is displayed on the console.

    Adding a delegate can be useful for posting your data directly back to your main thread, but you may need to use Invoke if some of the data items are not thread safe.

    class AnyTask {
    
        private object m_lock;
    
        public AnyTask() {
            m_lock = new object();
        }
        // Something to use the delegate
        public event MainDelegate OnUpdate;
    
        public void Test_Function(int count) {
            var list = new List(count);
            for (var i = 0; i < count; i++) {
                var thread = new Thread(new ParameterizedThreadStart(Thread_Task));
                var item = new Anything() {
                    Number = i,
                    Text = String.Format("Test_Function #{0}", i)
                };
                thread.Start(item);
                list.Add(thread);
            }
            foreach (var thread in list) {
                thread.Join();
            }
        }
    
        private void MainUpdate(Anything item, bool original) {
            if (OnUpdate != null) {
                OnUpdate(item, original);
            }
        }
    
        private void Thread_Task(object parameter) {
            lock (m_lock) {
                var item = (Anything)parameter;
                MainUpdate(item, true);
                item.Text = String.Format("{0}; Thread_Task #{1}", item.Text, item.Number);
                item.Number = 0;
                MainUpdate(item, false);
            }
        }
    
    }
    

    To test this, create a little Console Application, and put this in the Program.cs file:

    // A delegate makes life simpler
    delegate void MainDelegate(Anything sender, bool original);
    
    class Program {
    
        private const int COUNT = 15;
        private static List m_list;
    
        static void Main(string[] args) {
            m_list = new List(COUNT);
            var obj = new AnyTask();
            obj.OnUpdate += new MainDelegate(ThreadMessages);
            obj.Test_Function(COUNT);
            Console.WriteLine();
            foreach (var item in m_list) {
                Console.WriteLine("[Complete]:" + item.Text);
            }
            Console.WriteLine("Press any key to exit.");
            Console.ReadKey();
        }
    
        private static void ThreadMessages(Anything item, bool original) {
            if (original) {
                Console.WriteLine("[main method]:" + item.Text);
            } else {
                m_list.Add(item);
            }
        }
    
    }
    

    Here is a screenshot of what I got with this:

    Console Output

    I hope others can understand what I've tried to explain.

    I enjoy working on threads and using delegates. They make C# a lot of fun.

    Appendix: For VB Coders

    I wanted to see what was involved in writing the code above as a VB Console Application. The conversion involved a few things I didn't expect, so I will update this thread here for those wanting to know how to thread in VB.

    Imports System.Threading
    
    Delegate Sub MainDelegate(sender As Anything, original As Boolean)
    
    Class Main
    
        Private Const COUNT As Integer = 15
        Private Shared m_list As List(Of Anything)
    
        Public Shared Sub Main(args As String())
            m_list = New List(Of Anything)(COUNT)
            Dim obj As New AnyTask()
            AddHandler obj.OnUpdate, New MainDelegate(AddressOf ThreadMessages)
            obj.Test_Function(COUNT)
            Console.WriteLine()
            For Each item As Anything In m_list
                Console.WriteLine("[Complete]:" + item.Text)
            Next
            Console.WriteLine("Press any key to exit.")
            Console.ReadKey()
        End Sub
    
        Private Shared Sub ThreadMessages(item As Anything, original As Boolean)
            If original Then
                Console.WriteLine("[main method]:" + item.Text)
            Else
                m_list.Add(item)
            End If
        End Sub
    
    End Class
    
    Class AnyTask
    
        Private m_lock As Object
    
        Public Sub New()
            m_lock = New Object()
        End Sub
        ' Something to use the delegate
        Public Event OnUpdate As MainDelegate
    
        Public Sub Test_Function(count As Integer)
            Dim list As New List(Of Thread)(count)
            For i As Int32 = 0 To count - 1
                Dim thread As New Thread(New ParameterizedThreadStart(AddressOf Thread_Task))
                Dim item As New Anything()
                item.Number = i
                item.Text = String.Format("Test_Function #{0}", i)
                thread.Start(item)
                list.Add(thread)
            Next
            For Each thread As Thread In list
                thread.Join()
            Next
        End Sub
    
        Private Sub MainUpdate(item As Anything, original As Boolean)
            RaiseEvent OnUpdate(item, original)
        End Sub
    
        Private Sub Thread_Task(parameter As Object)
            SyncLock m_lock
                Dim item As Anything = DirectCast(parameter, Anything)
                MainUpdate(item, True)
                item.Text = [String].Format("{0}; Thread_Task #{1}", item.Text, item.Number)
                item.Number = 0
                MainUpdate(item, False)
            End SyncLock
        End Sub
    
    End Class
    
    
    Class Anything
        ' Number and Text are for instructional purposes only
        Public Property Number() As Integer
            Get
                Return m_Number
            End Get
            Set(value As Integer)
                m_Number = value
            End Set
        End Property
        Private m_Number As Integer
        Public Property Text() As String
            Get
                Return m_Text
            End Get
            Set(value As String)
                m_Text = value
            End Set
        End Property
        Private m_Text As String
        ' Data can be anything or another class
        Public Property Data() As Object
            Get
                Return m_Data
            End Get
            Set(value As Object)
                m_Data = value
            End Set
        End Property
        Private m_Data As Object
    End Class
    

提交回复
热议问题