C#中构建多线程应用程序[转] ----代码示例

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace 线程同步_线程异步
{

    //打印类
    public class Printer
    {
        //打印数字的方法
        public void PrintNumbers()
        {

            Console.WriteLine("-> {0} 正在执行打印任务,开始打印数字:", Thread.CurrentThread.Name);

            for (int i = 0; i < 10; i++)
            {

                Random r = new Random();

                //为了增加冲突的几率及,使各线程各自等待随机的时长

                Thread.Sleep(2000 * r.Next(5));

                //打印数字

                Console.Write("{0} ", i);

            }

            Console.WriteLine();

        }
    }

    //打印类

    public class Printer2
    {
        public void PrintNumbers()
        {

            //使用lock关键字,锁定d的代码是线程安全的

            lock (this)
            {

                Console.WriteLine("-> {0} 正在执行打印任务,开始打印数字:", Thread.CurrentThread.Name);

                for (int i = 0; i < 10; i++)
                {

                    Random r = new Random();

                    //为了增加冲突的几率及,使各线程各自等待随机的时长

                    Thread.Sleep(2000 * r.Next(5));

                    //打印数字

                    Console.Write("{0} ", i);

                }

                Console.WriteLine();

            }
        }

    }

    //也可以使用System.Threading命名空间下的Monitor类进行同步,两者内涵是一样的,但Monitor类更灵活,这里就不在做过多的探讨,代码如下:
    //打印类

    public class Printer3
    {

        public void PrintNumbers()
        {

            Monitor.Enter(this);
            try
            {

                Console.WriteLine("-> {0} 正在执行打印任务,开始打印数字:", Thread.CurrentThread.Name);

                for (int i = 0; i < 10; i++)
                {

                    Random r = new Random();

                    //为了增加冲突的几率及,使各线程各自等待随机的时长

                    Thread.Sleep(2000 * r.Next(5));

                    //打印数字

                    Console.Write("{0} ", i);

                }

                Console.WriteLine();

            }

            finally
            {

                Monitor.Exit(this);

            }

        }

    }

    class Program
    {
        //定义一个指向包含两个int型参数、返回值为int型的函数的委托
        public delegate int AddOp(int x, int y);
        static void Main(string[] args)
        {
            #region 线程demo1
            //Console.WriteLine("************** 显示当前线程的相关信息 *************");
            ////声明线程变量并赋值为当前线程
            ////Thread.CurrentThread得到的是执行当前代码的线程。
            //Thread primaryThread = Thread.CurrentThread;

            ////赋值线程的名称
            //primaryThread.Name = "主线程";
            ////显示线程的相关信息
            //Console.WriteLine("线程的名称:{0}", primaryThread.Name);
            //Console.WriteLine("线程是否启动?:{0}", primaryThread.IsAlive);
            //Console.WriteLine("线程的优先级{0}", primaryThread.Priority);
            //Console.WriteLine("线程的状态{0}", primaryThread.ThreadState);
            //Console.ReadLine();
            #endregion

            //前台线程与后台线程。前台线程能阻止应用程序的终止,既直到所有前台线程终止后才会彻底关闭应用程序。而对后台线程而言,当所有前台线程终止时,后台线程会被自动终止,不论后台线程是否正在执行任务。默认情况下通过Thread.Start()方法创建的线程都自动为前台线程,把线程的属性IsBackground设为true时就将线程转为后台线程。

            #region 异步调用线程 创建一个次线程执行打印数字的任务,而主线程则干其他的事,两者同时进行,互不干扰。 Demo2
            //Console.WriteLine("************* 两个线程同时工作 *****************");
            ////主线程,因为获得的是当前在执行Main()的线程
            //Thread primaryThread = Thread.CurrentThread;
            //primaryThread.Name = "主线程";
            //Console.WriteLine("-> {0} 在执行主线程 Main()。", Thread.CurrentThread.Name);

            ////次线程,该线程指向 PrintNumbers()方法
            //Thread SecondThread = new Thread(new ThreadStart(PrintNumbers));
            //// Thread SecondThread = new Thread(new ThreadStart(PrintNumbers)); 这一句做个解释。其实 ThreadStart 是 System.Threading 命名空间下的一个委托,其声明是 public delegate void ThreadStart(),指向不带参数、返回值为空的方法。所以当使用 ThreadStart 时,对应的线程就只能调用不带参数、返回值为空的方法。那非要指向含参数的方法呢?在System.Threading命名空间下还有一个ParameterizedThreadStart 委托,其声明是 public delegate void ParameterizedThreadStart(object obj),可以指向含 object 类型参数的方法,这里不要忘了 object 可是所有类型的父类哦,有了它就可以通过创建各种自定义类型,如结构、类等传递很多参数了,这里就不再举例说明了。

            //SecondThread.Name = "次线程";
            ////次线程开始执行指向的方法
            //SecondThread.Start();

            ////同时主线程在执行主函数中的其他任务
            //Console.WriteLine("正在执行主函数中的任务。。。。", "主线程在工作...");
            //Console.ReadLine();
            #endregion

            #region Demo3 并发问题
            ////,主线程产生的10个线程同时访问同一个对象实例printer的方法PrintNumbers(),由于没有锁定共享资源(注意,这里是指控制台),所以在PrintNumbers()输出到控制台之前,调用PrintNumbers()的线程很可能被挂起,但不知道什么时候(或是否有)挂起,导致得到不可预测的结果。

            //Console.WriteLine("********* 并发问题演示 *********");
            ////创建一个打印对象实例
            //Printer printer = new Printer();
            ////声明一个含5个线程对象的数组
            //Thread[] threads = new Thread[10];
            //for (int i = 0; i < 10; i++)
            //{

            //    //将每一个线程都指向printer的PrintNumbers()方法

            //    threads[i] = new Thread(new ThreadStart(printer.PrintNumbers));

            //    //给每一个线程编号

            //    threads[i].Name = i.ToString() + "号线程";
            //}
            ////开始执行所有线程

            //foreach (Thread t in threads)

            //    t.Start();

            //Console.ReadLine();

            #endregion

            #region Demo4 线程同步
            ////线程同步的访问方式也称为阻塞调用,即没有执行完任务不返回,线程被挂起。可以使用C#中的lock关键字,在此关键字范围类的代码都将是线程安全的。lock关键字需定义一个标记,线程进入锁定范围是必须获得这个标记。当锁定的是一个实例级对象的私有方法时使用方法本身所在对象的引用就可以了,将上面例子中的打印类Printer稍做改动,添加lock关键字,

            //Console.WriteLine("********* 并发问题演示 *********");
            ////创建一个打印对象实例
            ////Printer2 printer = new Printer2();
            //Printer3 printer = new Printer3();
            ////声明一个含5个线程对象的数组
            //Thread[] threads = new Thread[10];
            //for (int i = 0; i < 10; i++)
            //{

            //    //将每一个线程都指向printer的PrintNumbers()方法

            //    threads[i] = new Thread(new ThreadStart(printer.PrintNumbers));

            //    //给每一个线程编号

            //    threads[i].Name = i.ToString() + "号线程";
            //}
            ////开始执行所有线程

            //foreach (Thread t in threads)

            //    t.Start();

            ////Console.WriteLine("heihei");
            //Console.ReadLine();
            #endregion

            #region Demo5 委托
            ////创建一个指向包含两个int型参数、返回值为int型的函数的委托
            ////创建一个指向Add()方法的AddOp对象p
            //AddOp pAddOp = new AddOp(Add);
            ////使用委托间接调用方法Add()
            //Console.WriteLine("10 + 5 = {0}", pAddOp(10, 5));
            //Console.ReadLine();
            #endregion

            #region Demo6 线程异步
            ////观察上面的例子会发现,直接使用委托实例 pAddOp(10, 5) 就调用了求和方法 Add()。很明显,这个方法是由主线程执行的。然而,委托类型中还有另外两个方法——BeginInvoke()和EndInvoke()
            //Console.WriteLine("******* 委托异步线程 两个线程“同时”工作 *********");
            ////显示主线程的唯一标示
            //Console.WriteLine("调用Main()的主线程的线程ID是:{0}.", Thread.CurrentThread.ManagedThreadId);
            ////将委托实例指向Add2()方法
            //AddOp pAddOp = new AddOp(Add2);
            ////AddOp pAddOp = Add2;
            ////开始委托次线程调用。委托BeginInvoke()方法返回的类型是IAsyncResult,
            ////包含这委托指向方法结束返回的值,同时也是EndInvoke()方法参数
            //IAsyncResult iftAR = pAddOp.BeginInvoke(10, 10, null, null);
            //Console.WriteLine("nMain()方法中执行其他任务........n");
            //int sum = pAddOp.EndInvoke(iftAR);
            //Console.WriteLine("10 + 10 = {0}.", sum);
            //Console.ReadLine();
            #endregion

            #region Demo7 线程同步
            //委托中的线程同步主要涉及到上面使用的pAddOp.BeginInvoke(10, 10, null, null)方法中后面两个为null的参数,具体的可以参考相关资料。这里代码如下,解释见代码注释:
            Console.WriteLine("******* 线程同步,“阻塞”调用,两个线程工作 *********");

            Console.WriteLine("Main() invokee on thread {0}.", Thread.CurrentThread.ManagedThreadId);
            //将委托实例指向Add()方法
            AddOp pAddOp = new AddOp(Add3);
            IAsyncResult iftAR = pAddOp.BeginInvoke(10, 10, null, null);
            //判断委托线程是否执行完任务,

            //没有完成的话,主线程就做其他的事
            while (!iftAR.IsCompleted)
            {

                Console.WriteLine("Main()方法工作中.......");

                Thread.Sleep(1000);

            }
            //获得返回值

            int answer = pAddOp.EndInvoke(iftAR);

            Console.WriteLine("10 + 10 = {0}.", answer);

            Console.ReadLine();

            #endregion

        }

        //求和的函数
        static int Add(int x, int y)
        {
            int sum = x + y;
            return sum;
        }
        //求和方法
        static int Add2(int x, int y)
        {
            //指示调用该方法的线程ID,ManagedThreadId是线程的唯一标示

            Console.WriteLine("调用求和方法 Add()的线程ID是: {0}.", Thread.CurrentThread.ManagedThreadId);

            //模拟一个过程,停留5秒

            Thread.Sleep(5000);

            int sum = x + y;

            return sum;
        }

        //求和方法

        static int Add3(int x, int y)
        {

            //指示调用该方法的线程ID,ManagedThreadId是线程的唯一标示

            Console.WriteLine("调用求和方法 Add()的线程ID是: {0}.", Thread.CurrentThread.ManagedThreadId);

            //模拟一个过程,停留5秒

            Thread.Sleep(5000);

            int sum = x + y;

            return sum;

        }

        //打印数字的方法
        static void PrintNumbers()
        {

            Console.WriteLine("-> {0} 在执行打印数字函数 PrintNumber()", Thread.CurrentThread.Name);

            Console.WriteLine("打印数字: ");

            for (int i = 0; i < 10; i++)
            {

                Console.Write("{0}, ", i);

                //Sleep()方法使当前线程挂等待指定的时长在执行,这里主要是模仿打印任务

                Thread.Sleep(2000);

            }
            Console.WriteLine();

        }
    }
}
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace BackgroundWorker组件_线程异步
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        //BackgroundWorker组件
        //BackgroundWorker组件位于工具箱中,用于方便的创建线程异步的程序
        private void button1_Click(object sender, EventArgs e)
        {
            try
            {
                ////获得输入的数字
                int numOne = int.Parse(this.textBox1.Text);
                int numTwo = int.Parse(this.textBox2.Text);
                ////实例化参数类
                AddParams args = new AddParams(numOne, numTwo);
                //调用RunWorkerAsync()生成后台线程,同时传入参数
                this.backgroundWorker1.RunWorkerAsync(args);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
                //throw;
            }
        }

        //backgroundWorker新生成的线程开始工作
        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            //获取传入的AddParams对象
            AddParams args = (AddParams)e.Argument;
            //停留5秒,模拟耗时任务
            //Thread.Sleep(5000);
            Thread.Sleep(10000);
            //返回值
            e.Result = args.a + args.b;

        }

        //当backgroundWorker1的DoWork中的代码执行完后会触发该事件
        //同时,其执行的结果会包含在RunWorkerCompletedEventArgs参数中
        private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            //显示运算结果
            MessageBox.Show("运行结果为:" + e.Result.ToString(), "结果");
        }
    }

    //参数类,这个类仅仅起到一个记录并传递参数的作用
    class AddParams
    {

        public int a, b;

        public AddParams(int numb1, int numb2)
        {

            a = numb1;

            b = numb2;

        }

    }
    //注意,在计算结果的同时,窗体可以随意移动,也可以重新在文本框中输入信息,这就说明主线程与backgroundWorker组件生成的线程是异步的。
}

原文地址:https://www.cnblogs.com/cjm123/p/8473328.html

时间: 2024-10-11 04:15:23

C#中构建多线程应用程序[转] ----代码示例的相关文章

java中的List详解以及代码示例

一:概念List是Java集合Collection中的一个接口,一般用ArrayList类和LinkedList类去实现这个接口.Collection集合还有其他接口:Map,Set(在我的另一篇博客)二:LIST的使用List的常用方法 boolean add(E e) //尾插 e void add(int index, E element) //将 e 插入到 index 位置 boolean addAll(Collection<? extends E> c) //尾插 c 中的元素 E

Java中的多线程 模拟网络抢票代码

一.抢票类: package cn.jbit.ticket; public class Ticket implements Runnable { private int num = 0; // 出票数 private int count = 10; // 剩余票数 boolean flag = false; @Override public void run() { while (true) { // 没有余票时,跳出循环 if (count <= 0) { break; } num++; co

软件开发中的自测及C代码示例

在软件开发中,程序自测是一个永远都绕不开的话题.很多开发人员以写出有难度的代码为荣,但却不重视对自己编写的代码进行测试,这导致了最终到达客户手中的产品质量不高,bug频发,损害了公司的形象.对于一个开发人员来说,我们应该将开发和自测置于同等重要的地位,我们花在自测上的时间要不比开发少.能否对自己编写的代码进行充分的自测也是检验一个开发人员水平高低的标准之一. 自测方法 根据所编写的程序的特点,自测方法大致有如下几种: 第一种,利用模拟工具进行自测.这种方法适用于需要其他模块(尚不具备)发过来的消

浅谈 PHP 中的多种加密技术及代码示例

信息加密技术的分类 单项散列加密技术(不可逆的加密) 属于摘要算法,不是一种加密算法,作用是把任意长的输入字符串变化成固定长的输出串的一种函数 MD5 string md5 ( string $str [, bool $raw_output = false ] ); //MD5加密,输入任意长度字符串返回一个唯一的32位字符 md5()为单向加密,没有逆向解密算法,但是还是可以对一些常见的字符串通过收集,枚举,碰撞等方法破解;所以为了让其破解起来更麻烦一些,所以我们一般加一点盐值(salt)并双

php中的mongodb select常用操作代码示例【转载】

前面说到了mongodb安装,配置,集群,以及php的插入与更新等,请参考:mongodb.下面说一下,mongodb select的常用操作 测试数据: 复制代码代码如下: { "_id" : 1, "title" : "红楼梦", "auther" : "曹雪芹", "typeColumn" : "test", "money" : 80, &q

ECMAScript 6 中的快捷语法汇总及代码示例

对于每个 JavaScript 开发人员,快捷语法都是必备技能之一,下面就集中介绍这些快捷语法. 三元运算符 传统写法 const x = 20; let answer; if (x > 10) { answer = 'is greater'; } else { answer = 'is lesser'; } 快捷语法 const answer = x > 10 ? 'is greater' : 'is lesser'; 空值判定 传统写法 if (variable1 !== null ||

Java中的七种排序方式代码示例

package baseJava; /** * @title SortMethods.java * @author DonsenChen * @Date 2018年5月2日 上午10:16:03 * @Description */ public class SortMethods { public static void main(String[] args) { int[] arr = { 3, 7, 9, 1, 4, 8, 2, 6, 5 }; binarySort(arr); bubble

Java程序员面试中的多线程问题

很多核心Java面试题来源于多线程(Multi-Threading)和集合框架(Collections Framework),理解核心线程概念时,娴熟的实际经验是必需的.这篇文章收集了Java线程方面一些典型的问题,这些问题经常被高级工程师所问到. 0.Java中多线程同步是什么? 在多线程程序下,同步能控制对共享资源的访问.如果没有同步,当一个Java线程在修改一个共享变量时,另外一个线程正在使用或者更新同一个变量,这样容易导致程序出现错误的结果. 1.解释实现多线程的几种方法? 一Java线

java程序中的多线程(转)

为什么会排队等待? 下面的这个简单的 Java 程序完成四项不相关的任务.这样的程序有单个控制线程,控制在这四个任务之间线性地移动.此外,因为所需的资源 ― 打印机.磁盘.数据库和显示屏 -- 由于硬件和软件的限制都有内在的潜伏时间,所以每项任务都包含明显的等待时间.因此,程序在访问数据库之前必须等待打印机完成打印文件的任务,等等.如果您正在等待程序的完成,则这是对计算资源和您的时间的一种拙劣使用.改进此程序的一种方法是使它成为多线程的. 四项不相关的任务 class myclass { sta