• [C#参考]主线程和子线程之间的参数传递


    几个进程在大多数情况下要包含很多的子线程,那么他们之间免不了的要互相传递很多的参数,那么参数怎么传递的呢?


    主线程向子线程传递参数的方法


    第一种方法:Thraed类有一个带参数的委托类型的重载形式,这个委托的定义如下:

    public delegate void ParameterizedThreadStart(Object obj)

    这个Thread类的构造方法的定义如下:

    public Thread(ParameterizedThreadStart start);

    下面的代码使用了这个带参数的委托向线程传递一个字符串参数:

    public static void myStaticParamThreadMethod(Object obj)
    {
        Console.WriteLine(obj);
    }
     
    static void Main(string[] args)
    {
        Thread thread = new Thread(myStaticParamThreadMethod);
        thread.Start("通过委托的参数传值");
    }

    注意这种形式,委托就是Thread要执行的方法,这个委托有一个类的实例对象作为参数。然后在Thread的Start()方法中把这个对象传进去。

    如果使用了不带参数的委托,当然也能很正常的启动线程,别学傻了。

    第二种方法:定义一个类来传递参数

    class Program
        {
            static void Main(string[] args)
            {
                MyData myData = new MyData("abcd", 1234);
                Thread thread = new Thread(myData.ThreadMethod);
                thread.Start();
    
                Console.ReadKey();
            }
        }//class
    
        //定义一个类传递参数
        public class MyData
        {
            private string d1;
            private int d2;
    
            public MyData(string d1, int d2)
            {
                this.d1 = d1;
                this.d2 = d2;
            }
    
            public void ThreadMethod()
            {
                Console.WriteLine(d1);
                Console.WriteLine(d2);
            }
        }//class

    这种方法的特点是:子线程的执行入口是在另一个类中,这样正好可以借助这个类的成员函数,给子线程传参。

    第三种方法:定义一个新的线程类,让所有的子线程类都继承自这个类

    abstract class MyThread
    {
        Thread thread = null;
     
        abstract public void run();
     
        public void Start()
        {
            if (thread == null)
            {
                thread = new Thread(run);
                thread.Start();
            }
        }
    }
    class Utility : MyThread
    {
        private string d1;
        private int d2;
     
        public override void run()
        {
            Console.WriteLine(d1);
            Console.WriteLine(d2);
        }
     
    }//class

    其实上面的两种方法的原理是一样的,这是一个面向数据,一个面向线程。


    子线程向主线程传递参数


    这里看到是传递参数,也就是说子线程要调用主线程的一个方法,然后把参数传递给主线程的那个方法。说一下方法是前面已经讲过的Invoke和BeginInvoke,但是那时调用主线程的方法并没有传递参数,今天看一下带参数的调用主线程的指定方法。

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;
    using System.Threading;
    
    namespace WindowsFormsApplication3
    {
        public partial class Form1 : Form
        {
            private int count = 0;
    
            private delegate void DoWorkUIThreadDelegate();
            public Form1()
            {
                InitializeComponent();
            }
    
            private void btnStart_Click(object sender, EventArgs e)
            {
                Thread thread = new Thread(ThreadMethod);
                thread.IsBackground = true;
                thread.Start();
            }
    
            private void ThreadMethod()
            {
                while (true)
                {
                    //lblResult.Text = DateTime.Now.ToString();
                    //这句话不能直接调用,因为子线程不能直接调用UI线程中的控件
                    if (this.InvokeRequired)
                    {
                        this.BeginInvoke(new DoWorkUIThreadDelegate(DoWorkUIThread), null);
                    }
                    else
                    {
                        DoWorkUIThread();
                    }
    
                    //子线程还是可以访问UI线程的普通变量的,只是不能访问控件
                    //因为普通变量是属于整个类的,属于整个进程的,各个线程时共享的
                    //对访问共享的数据,加一个lock的锁更加的好
                    count++;
                    Thread.Sleep(1000);
                }
                
            }
    
            private void DoWorkUIThread()
            {
                txtTime.Text = DateTime.Now.ToString() + " " + count;
            }
        }
    }

    上面的这种情况似乎用不着子线程给UI线程返回数据,反正子线程可以访问主线程的成员变量。但是另一种情况来了,当子线程不再UI线程所在的类的时候,也就是说子线程在一个工具类中,UI类new出来一个工具类完成一定的工作,UI类可以初始化工具类,但是工具类完成了一定任务后怎么通知UI类呢?现在有这种假设:

    UI类要Socket连接网络,现在有一个SocketUtil工具可以完成这项任务,所以UI类就New出来一个SocketUtil,然后调用指定的函数,把IP和Port传递进去。在完成了一些任务以后,SocketUtil要反馈一些信息给UI类。让UI类显示反馈的信息。现在面临两个问题:

    1. UI类怎么知道SocketUtil完成了这项任务,然后取显示数据呢?

    2. UI类即使知道了什么时候显示信息,那么要显示的内容,UI类怎么知道是什么呢?

    第一个问题的解决方法就是事件,利用事件就能在SocketUtil完成一些任务之后,通知UI类接下来怎么做。

    第二个问题就是利用Invoke让子线程给主线程调用主线程的函数完成任务的时候,给一些参数。

    这里就直接在同一个类中展示一下:

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;
    using System.Threading;
    
    namespace WindowsFormsApplication3
    {
        public partial class Form1 : Form
        {
            private int count = 0;
    
            private delegate void DoWorkUIThreadDelegate(string name, int id);
            public Form1()
            {
                InitializeComponent();
            }
    
            private void btnStart_Click(object sender, EventArgs e)
            {
                Thread thread = new Thread(ThreadMethod);
                thread.IsBackground = true;
                thread.Start();
            }
    
            private void ThreadMethod()
            {
                string strName = "stemon";
                int ID = 1;
    
                while (true)
                {
                    //lblResult.Text = DateTime.Now.ToString();
                    //这句话不能直接调用,因为子线程不能直接调用UI线程中的控件
                    if (this.InvokeRequired)
                    {
                        object[] myArray = new object[2];
                        //类型的装箱是自动的
                        //类型的拆箱要强制转换
                        myArray[0] = strName;
                        myArray[1] = ID;
    
                        this.BeginInvoke(new DoWorkUIThreadDelegate(DoWorkUIThread), myArray);
                    }
                    else
                    {
                        //DoWorkUIThread(strName, ID);
                    }
    
                    //子线程还是可以访问UI线程的普通变量的,只是不能访问控件
                    //因为普通变量是属于整个类的,属于整个进程的,各个线程时共享的
                    //对访问共享的数据,加一个lock的锁更加的好
                    count++;
                    Thread.Sleep(1000);
                }
                
            }
    
            private void DoWorkUIThread(string name, int id)
            {
                txtTime.Text = name + " " + id + " " + DateTime.Now.ToString() + " " + count;
            }
        }
    }

    这个方法是这样操作的,BeginInvoke可以传递一个数组,这个数组是boject类型的,这样就可以把所有的参数都装箱成object类型的,弄成一个object类型的数组,然后到调用方在拆封就可以了。

  • 相关阅读:
    redis 储存对象
    redis key 查看器
    c# 控制台程序编写RabbitMQ 生产者
    C# 使用Topshelf 构建 基于 window 服务的 RabbitMQ消费端
    asp.net webapi 使用定时任务Hangfire
    asp.net webpi 中使用 ClientHelper 发起HTTP请求
    SQL Server 导入和导出向导 未在本地计算机上注册Mircrosoft.ACE.OLEDB.12.0 提供程序
    c# 使用Linq 表达式 对查询结果分组,保留价格最低的一条
    Asp.Net s请求报传输流收到意外的 EOF 或 0 个字节
    asp.net webapi 中使用rdlc 报表
  • 原文地址:https://www.cnblogs.com/stemon/p/4214906.html
Copyright © 2020-2023  润新知