• 多线程,匿名委托,异步调用


    简单的线程处理 及同步:

    public class MuThread
    {
        int a = 0;
    
        int i = 0;
        private volatile bool _run=true;
        public void method(object par)
        {
            while (_run)
            {
                Console.WriteLine("运行中"+par.ToString());
            }
            Console.WriteLine("已结束");
            
        }
        public void stop()
        {
            _run = false;
        }
    
        public void method1()
        {
            while (a < 100)
            {
                a++; Console.WriteLine("线程1输出:" + a);
            }
        }
        public void method2()
        {
            //当不加入线程同步代码的时候调用method1跟method2 会出现混乱
            //但是通过数他们的输出行数依然是100行 
            //说明while判断是正确的 
            //当CPU分配时间片的时候 无论他们有多么接近 其实同一时间依然只有一个线程在访问变量a
    
            //但是线程1跟2是CPU随机分配时间片交替前进的 实现同一时间多个进度协同执行任务的效果
    
            while (a < 100)
            {
                a++; Console.WriteLine("线程2输出:" + a);
            }
        }
    
        public void methodSyn1()
        {
            while (a < 100)
            {
                lock (this)
                {
                    //意思是代码进入lock范围后 大括号内的代码将会被单独占用直到执行完
                    //而不会临时被其他时间片插入导致a的值已经更改
                    //当时间片继续回到此段时还沿用原来的 变量 导致混乱
                    //如果去掉前面的判断 会输出101 ,至于原理么跟孙鑫C++线程同步是一样的 也有Monitor.Entry()
                    if (a < 100)
                    {
                        a++; Console.WriteLine("线程1输出:" + a);
                    }
                }
            }
        }
    
        public void methodSyn2()
        {
            while (a < 100)
            {
                Monitor.Enter(this);
                if (a < 100)
                {
                    a++; Console.WriteLine("线程2输出:" + a);
                }
                Monitor.Exit(this);
            }
        }
    }
    

    线程示例:

    static void Main()
    {
        //Service s = new Service();
        //s.start();
    
        //初始化MuThread的时候可以在构造函数 中传入一个方法引用也就是delegate
        //然后再MuThread实例的线程方法执行完毕后调用该delegate 
        //这种编程方式我一直认为很高深 被那些砖家称之为"回调"callback
        //参见ms-help://MS.VSCC.v90/MS.MSDNQTR.v90.chs/dv_fxadvance/html/52b32222-e185-4f42-91a7-eaca65c0ab6d.htm
        MuThread m = new MuThread();
    
        //ThreadStart 其实是一个委托
        //在C++里就需要声明委托 
        //为了给方法传参数但是不能为每种类型都定义一个委托 所以只能传入object类型
    
        //.Net为我们简化了的语法
        Thread tPar = new Thread(m.method);
        tPar.Start("传入的参数");
    
        //ParameterizedThreadStart委托显示语法 start()其实相当于Event.do()            
        ParameterizedThreadStart del = new ParameterizedThreadStart(m.method);
        Thread tPar2 = new Thread(del);
        tPar2.Start("传入的参数");
    
        Thread t = new Thread(new ThreadStart(m.method1));
        Thread t2 = new Thread(new ThreadStart(m.method2));
        t2.Start();
        t.Start();
        //利用volatile 参数的状态终止线程
        while (!tPar.IsAlive) ;
    
        Thread.Sleep(100);
        m.stop();
        //MSDN的意思是阻断当前调用t的线程 也就是Main 主线程 直到让t执行完毕
        //事实确实是这样的 当不加Join()的时候 看着t.start()的语句在main方法下面的循环语句前面
        //其实他们的时间片依然由CPU随机分配的 "主线程调用"这句输出是穿插在前面子线程输出一起的
        //参见ms-help://MS.VSCC.v90/MS.MSDNQTR.v90.chs/fxref_mscorlib/html/56ed7b6f-efe0-67e7-34bc-766dd9f693f9.htm
        //当主线程 也就是Main方法里进行Thread.Sleep(200)时 其实是挂起主线程 这样就可以把时间片让给那些子线程
        t.Join();
        for (int i = 0; i < 50; i++)
        {
            Console.WriteLine("主线程调用");
        }
    
        //使用线程池
        //ms-help://MS.VSCC.v90/MS.MSDNQTR.v90.chs/dv_csref/html/5426dae4-c3f3-4e76-a998-19f7ca4baf3f.htm
        Console.ReadKey();
    }
    

     又反复测试了下join其实感觉就像endInvoke 就是阻止,说白了把指定的线程join到当前主线程 说白了就是阻塞操作 可不就是endInvoke么  ,到trd.Join()的 地方位置 必须要等待trd执行完毕

    使用backgroundworker组件:

    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            backgroundWorker1.WorkerReportsProgress = true;
            backgroundWorker1.WorkerSupportsCancellation = true;
            button3.Enabled = false;
        }
    
        private void button2_Click(object sender, EventArgs e)//start
        {
            textBox1.Text = "开始产生10000以内的随机数。。。\n\n";
            button2.Enabled = false;
            button3.Enabled = true;
            //在后台开始操作
            backgroundWorker1.RunWorkerAsync();
        }
    
        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            //不要直接使用组件实例名称(backgroundworker1)因为有多个backgroundworker时
            //直接使用会产生耦合问题 应该通过下面的转换使用它
            BackgroundWorker worker = sender as BackgroundWorker;
            //下面的内容相当于线程要处理的内容。//注意 不要在此事件中和界面控件打交道
            Random r = new Random();
            int numCount = 0;
            while (worker.CancellationPending==false)
            {
                int num = r.Next(10000);
                if (num%5==0)
                {
                    numCount++;
                    worker.ReportProgress(0, num);
                    Thread.Sleep(1000);
                }
            }
            e.Result = numCount;
        }
    
        private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            int num = (int)e.UserState;
            textBox1.Text += num + " ";
        }
    
        private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Error==null)
            {
                textBox1.Text += "\n\n操作停止,共产生" + e.Result + "个能被5整除的随机数";
            }
            else
            {
                textBox1.Text += "\n操作过程中产生错误:" + e.Error;
            }
        }
    
        private void button3_Click(object sender, EventArgs e)
        {
            backgroundWorker1.CancelAsync();
            button3.Enabled = false;
            button2.Enabled = true;
        }
    
    }
    

    一些关于匿名委托 和lambda表达式的写法 ,还有异步调用:

      1 public void callDel(Func<int,int,int> dd)
      2         {
      3             int rst = dd.Invoke(5, 2);
      4             Console.WriteLine("call Func rst is:{0}", rst);
      5         }
      6 
      7         public int method1()
      8         {
      9             
     10             //delDone.WaitOne(2000);
     11             Thread.Sleep(2000);
     12             
     13             return 1;
     14         }
     15 
     16         public delegate int MyDele();
     17 ManualResetEvent delDone = new ManualResetEvent(false);
     18         private void Form3_Load(object sender, EventArgs e)
     19         {
     20 
     21             //waitone的作用 仅仅是阻断当前行代码以后的部分继续执行
     22             //然后在回调里证明已经回调已经完成了  继续放行
     23             //实际上是一种失去异步意义的一种方式 ,线程同步
     24             delDone.Reset();
     25             MyDele d4 = new MyDele(method1);
     26             d4.BeginInvoke((iar) =>
     27             {
     28                 int rdmResult = d4.EndInvoke(iar);
     29                 Console.WriteLine("iar call back state :" + iar.AsyncState.ToString());
     30                 Console.WriteLine("iar call back rst is :{0}", rdmResult);
     31                 delDone.Set();
     32             }, "ss");
     33             //delDone.Set();
     34             delDone.WaitOne(1000);
     35             Console.WriteLine("lalalala....");
     36 
     37             return;//----------------------------------------------------------------------------------------------------
     38             var cl = new {name="xiang",age=21};
     39             Console.WriteLine(cl.name);
     40             return;//-----------------------------------------------------------------------------------------------------
     41             //调用func  调用func 的直接好处就是 让你连委托声明 那句都省了
     42             //说白了就是你传一段代码进来 我来执行 ,那么你传的这段代码就是参数 。你只需要把方法原型作为形参定义好
     43             //感觉完全一锅写 有点类似于脚本语言的写法
     44             //上面是lambda写法 下面是 匿名委托写法
     45             callDel((num1, num2) => {
     46                 return num1 + num2;
     47             });
     48             callDel((num1, num2) => {
     49                 return num1 - num2;
     50             });
     51 
     52             callDel(delegate (int num1, int num2) {
     53                 return num1 * num2;
     54             });
     55 
     56             MyDele d2 = delegate ()
     57             {
     58                 Console.WriteLine("call myDel2....");
     59                 return 0;
     60             };
     61             d2();
     62 
     63             MyDele d3 = new MyDele(
     64             delegate {
     65                 Console.WriteLine("call myDel3....");
     66                 return 0;
     67             });
     68             d3();
     69 
     70             return;//-----------------------------------------------------------------------------------------------
     71             //异步回调
     72             MyDele d1 = new MyDele(() => {
     73                 //MessageBox.Show("mydel process");
     74                 Console.WriteLine("mydel start");
     75                 Thread.Sleep(2000);
     76                 Console.WriteLine("mydel end");
     77                 return new Random().Next();
     78             });
     79             //d1.Invoke();
     80 
     81             IAsyncResult iars= d1.BeginInvoke((iar) =>
     82             {
     83                 //委托内容执行完成 后的回调
     84 
     85                 //iar 可以理解为特定的线程的句柄 进行回溯的 找到我们当初调用的 那个方法
     86                 //从而获取到 方法执行的结果 ,endinvolve 代表实质性的异步调用结束 可获得实实在在的执行结果
     87                 //既然执行到这里了 那么自然代表可以正常endinvoke了。
     88                 int rdmResult = d1.EndInvoke(iar);
     89                 Console.WriteLine("iar call back state :" + iar.AsyncState.ToString());
     90                 Console.WriteLine("iar call back rst is :{0}",rdmResult);
     91             }, "ss");
     92 
     93             //执行到这里 你无法确定能否 IsCompleted 啊 ,如果强行endinvoke  不就市区异步的意义了么,
     94             //d1.EndInvoke(iars);
     95 
     96             //比如这里我们等待3秒钟 没有执行完成 就结束线程
     97 
     98             //wait one 就是阻塞主线程 把时间片完全让给 异步委托去执行 ,等待异步委托执行完成 。也是一种失去异步的意义的一种方式
     99             //waitone 的时间 并不代表一定需要执行那么长时间,如果不带时间参数表示等待直至异步线程完成
    100             iars.AsyncWaitHandle.WaitOne();
    101             Console.WriteLine("wait one 1000");
    102             //Thread.Sleep(3000);
    103             //if (iars.IsCompleted)
    104             //    Console.WriteLine("mydel is complete");
    105             //else
    106             //{
    107             //    Console.WriteLine("mydel is not complete");
    108             //}
    109             return;//---------------------------------------------------------------------------------------------------
    110             //空参数 的lambda 委托写法 去掉action 一样的效果
    111             Thread t1 = new Thread(new ThreadStart( new Action(()=>
    112             {
    113                 MessageBox.Show("t1 process");
    114             })));
    115             t1.Start();
    116             return;//-----------------------------------------------------------------------------------------------------
    117             //用lambda的方式来写事件绑定
    118             button2.Click += new EventHandler((sender2, e2) =>
    119             {
    120                 MessageBox.Show("hellow");
    121             });
    122 
    123             //Func 是一个带返回值形式  委托 ,就是微软新搞的一种花样  就是委托
    124             //也可用lambda 的方式来写
    125             List<string> strArr = new List<string>() {
    126                 "xiang",
    127                 "zhang",
    128                 "chen"        };
    129             //var sel = strArr.Where(wheretest);
    130             var sel = strArr.Where((r) =>
    131             {
    132                 if (r.Contains("g"))
    133                     return true;
    134                 else
    135                     return false;
    136             });
    137 
    138             //lamda 方式的action
    139             sel.ToList().ForEach(i =>
    140             {
    141                 Console.WriteLine(i);
    142             });
    143 
    144             return;//-----------------------------------------------------------------------------------------------------
    145             List<int> arr = new List<int>();
    146             arr.Add(23);
    147             arr.Add(45);
    148             arr.Add(22);
    149             arr.ForEach((i) =>
    150            {
    151                Console.WriteLine(i + "");
    152            });
    153         }

     每次看都有不一样的东西,看山不是山 ,人生就是不断的学习。以前以为异步调用就是简单的分一个通道来做事情 ,还真不是那么简单

     1 mydel d;
     2 private void button3_Click(object sender, EventArgs e)
     3 {
     4 
     5     d = new mydel(deldo);
     6     Console.WriteLine("aaa");
     7     //注意下面的d.BeginInvoke(null,null);并不一定要传入asyncCallBack ,根据你情况定 ,
     8     //比如你不需要得到异步调用的结果 (那还不如task.run() ? thread.start()?
     9     //注意 注意 注意 再次说明 这个asynCallBack 在异步方法调用完成后 才会执行 ,仅仅是一个获取结果用 并无特别意思
    10 
    11     //IAsyncResult ar= d.BeginInvoke(null,null);
    12     //deldoend这个方法只有结束时才会调 ,只是相当于结束时候的一个通知 并没有其他意思
    13     //如果不这样写 你就无法确定调用何时结束,当然你也可以 在begininvoke 后 同步做一些其他事, 
    14     //在最终的时候使用ar.synchandle.waitOne 等待调用结束 ,由此来做到不同线程的同步
    15     IAsyncResult ar = d.BeginInvoke(deldoEnd, "hhh");
    16     //hhh为你想自定义传入end方法里的参数 end方法里使用ar.asyncState获取
    17     Console.WriteLine("bbb");
    18 
    19     //Thread.Sleep(4000);
    20     //Console.WriteLine("rstttt"+d.EndInvoke(ar));
    21 
    22 }
    23 
    24 public int deldo()
    25 {
    26     Console.WriteLine("ccc");
    27     Thread.Sleep(3000);
    28     Console.WriteLine(555);
    29     return 5;
    30 }
    31 
    32 public void deldoEnd(IAsyncResult ar)
    33 {
    34     Console.WriteLine("ddd");
    35     int rest = d.EndInvoke(ar);
    36     Console.WriteLine(ar.AsyncState.ToString());
    37     Console.WriteLine(rest);
    38 }
    39 
    40 delegate int mydel();

     又是一些新的Task特性的使用方式,还是线程只不过换了种方式:

    https://www.cnblogs.com/lonelyxmas/p/9509298.html

    https://www.cnblogs.com/jesse2013/p/async-and-await.html

    https://www.cnblogs.com/CreateMyself/p/5983208.html

  • 相关阅读:
    Mysql数据库分库备份,分表备份
    KICKSTART无人值守安装
    git的使用
    iowait 过高问题的查找及解决linux
    Redis配置文件redis.conf详解
    安装和使用ZFS
    GlusterFS配置及使用
    Ceph与Gluster之开源存储的对比
    去掉Tomcat的管理页面
    Tomcat不加项目名称访问设置
  • 原文地址:https://www.cnblogs.com/assassinx/p/2757601.html
Copyright © 2020-2023  润新知