c#基础5 进程


进程与线程的一个简单解释 - 阮一峰的网络日志

进程 主线程和分线程关系

一个程序就是一个进程,然而进程里面包含若干个线程,而每个进程里面都有一个(可以说必须要有一个)线程,这个线程就是主线程,然而主线程有一天发现自己的工作太多了,在规定的时间内完不成工作,这时候他就召唤了一个小弟(子线程)帮他,他给小弟分配了一些任务,当小弟做完了分配给他的任务后,他就把小弟赶走了!这就是主线程和子线程。

  有4种创建线程的方式:

  • 1.Thread 自己创建的独立的线程, 优先级高,需要使用者自己管理。
                //创建线程1
     
                //创建分线程执行哪个方法
                ThreadStart childref = new ThreadStart(CallToChildThread);
                //创建分线程实例对象
                Thread childThread = new Thread(childref);     
                //执行分线程
                childThread.Start();
                 public static void CallToChildThread()
             {
               
               
                  while (true)
                {
     
                    Console.WriteLine("执行繁重的任务");
                }
              
                
              }
     
     
     
    //  简写
                Thread childThread = new Thread(() => {
                    while (true)
                    {
     
                        Console.WriteLine("执行繁重的任务");
                    }
                });
     
     
                 //线程暂停2
                 //创建分线程执行哪个方法
                ThreadStart childref = new ThreadStart(CallToChildThread);
                //创建分线程实例对象
                Thread childThread = new Thread(childref);
                // 设置线程的名字
                childThread.Name = "分线程1";
                //执行分线程
                childThread.Start();
            
                 public static void CallToChildThread()
             {
               
                 //线程休眠  当把方法写在哪个线程中就休眠哪个线程
                 Thread.Sleep(3000);
               
                      while (true)
                {
     
                    Console.WriteLine("执行繁重的任务");
                }
              
                
              }
        
     
     
    //线程销毁
    1.线程方法Method执行完结,线程自动销毁
    2.如果是无限循环需要手动销毁
     
     
     
     
                //创建线程
     
                //创建分线程执行哪个方法
                ThreadStart childref = new ThreadStart(CallToChildThread);
                //创建分线程实例对象
                Thread childThread = new Thread(childref);
                childThread.Name = "分线程1";
                //执行分线程
                childThread.Start();
                //线程休眠  当把方法写在哪个线程中就休眠哪个线程
                 Thread.Sleep(3000);
     
                //销毁线程
                childThread.Abort();
                Console.WriteLine("haha");
     
     
            }
     
            public static void CallToChildThread() {
             
                while (true)
                {
     
                    Console.WriteLine("111111");
                }
              
                
            }
     
     
    线程函数通过委托传递,可以不带参数,也可以带参数(只能有一个参数)
     Thread t2 = new Thread(new ParameterizedThreadStart(TestMethod));
     t2.Start("hello");
     
      public static void TestMethod(object data)
            {
                string datastr = data as string;
                Console.WriteLine("带参数的线程函数,参数为:{0}", datastr);
            }
     
     
      //简写
      Thread t2 = new Thread((e) => { Console.WriteLine("带参数的线程函数,参数为:{0}", e); });
      t2.Start("hello");
     
     
     
    线程阻塞 Join()  线程之间执行顺序默认是无关的  为了保持同步  使用join()
               
     
                Thread thread1 = new Thread(() => 
                { 
                    Console.WriteLine("2"); 
                });
                Thread thread2 = new Thread(() => { 
                   //线程同步
                    thread1.Join();
                     Console.WriteLine("3"); 
                
                });
                Thread thread3 = new Thread(() => { 
                    thread2.Join();
                    Console.WriteLine("4");
                });
                thread1.Start();
              
                thread2.Start();
              
                thread3.Start();
     
     
     
    线程抢占   如果两个线程同时对某个资源进行同时访问  就可能出现 线程抢占 
     
            static  bool done;
            static void Main(string[] args)
            {
                  
                new Thread(Go).Start();
                Go();
                Console.ReadKey();
            }
     
            static  void Go()
            {
                if (!done)
                {
                    Console.WriteLine("Done");
                    done = true;
                }
            }
     
     
    解决线程抢占问题 使用线程锁
             static  readonly object locker = new object();  //线程锁对象
            static  bool done;
            static void Main(string[] args)
            {
                  
                new Thread(Go).Start();
                
                Go();
                Console.ReadKey();
            }
     
     
            static  void Go()
            {
                //lock关键字 线程锁  (唯一的对象)
                lock (locker)
                {
     
                    if (!done)
                    {
                        Console.WriteLine("Done");
                        done = true;
                    }
                }
               
            }
     
     
    前台线程与后台线程  
    前台线程会随着主线程窗口关闭而停止,后台线程及时主线程窗口关闭自己独立运行。
    IsBackground 设置是否是前后台线程
        Thread worker = new Thread(() => Console.ReadLine());
        worker.IsBackground = true;  
        worker.Name = "backThread";
        worker.Start();
        Console.WriteLine("finish!");
     

       进程和线程的理解

//1.Task位于using System.Threading.Tasks;命名空间下

2.Task和ThreadPool一样 都是线程池操作

  • 2.ThreadPool 线程池
  •  线程和线程池都是进行多线程操作的,线程池是用来保存线程的一个容器,在程序创建线程来执行任务的时候线程池才会初始化一个线程,线程在执行完毕之后并不会被销毁,而是被挂起等待下一个任务的到来被激活执行任务,当线程池里的线程不够用的时候会新实例化一个线程,来执行,线程池里的线程会被反复利用。

     
    方式一:
    QueueUserWorkItem 接收一个参数,参数类型是WaitCallback 它是一个无返回值委托,委托函数接收一个obejct类型参数。
    官方定义:public delegate void WaitCallback(object state);
     
     
     
       WaitCallback callBack = DoSomething;
       ThreadPool.QueueUserWorkItem(callBack);
      
      static void DoSomething(object obj)
      {
         Console.WriteLine("do something");
      }
     
     
    以上代码可以简写, waitCallback委托赋值一个匿名方法
     
    WaitCallback waitCallback = arg => Console.WriteLine("dosomething1");
    ThreadPool.QueueUserWorkItem(waitCallback)
     
    继续简写
    ThreadPool.QueueUserWorkItem(e =>
    {
        Console.WriteLine("do something2");
    });
     
     
     
     
    方式二:
    QueueUserWorkItem 接收两个参数,第一个参数是WaitCallback 委托类型,第二个参数是object对象,用于传递给委托函数
     
    参数"dosomething3"将传递给委托函数DoSomething
     
     
     
    static void DoSomething(object value)
    {
        Console.WriteLine(value);
    }
     
    WaitCallback waitCallback1 = DoSomething;
    ThreadPool.QueueUserWorkItem(waitCallback1, "dosomething3");
     
     
    以上代码简写
    使用匿名函数进行简写:
     
    ThreadPool.QueueUserWorkItem(e =>
    {
        DoSomething(e);
    }, "dosomething4");
     
     
     
     
     
    线程休眠
                
                //ManualResetEvent mreset = new ManualResetEvent(false);
              ThreadPool.QueueUserWorkItem(e =>
                {
                    Thread.Sleep(2000);
                      Console.WriteLine("dosomething");
                  //  mreset.Set();
                });
                Console.WriteLine("dosomething else...");
                Console.WriteLine("dosomething else...");
               //阻塞主线程 等待分线程完成后 执行mreset.Set()后执行后续代码
                 mreset.WaitOne();

  • 3.net4.0在ThreadPool的基础上推出了Task类
  • ThreadPool相比Thread来说具备了很多优势,但是ThreadPool却又存在一些使用上的不方便◆ ThreadPool不支持线程控制,线程延续 ,线程取消
  •  task 解决了 以上问题
  • //1.Task位于using System.Threading.Tasks;命名空间下

    2.Task和ThreadPool一样 都是线程池操作

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
 
namespace DemoAsync
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Task   With Thread  Start !");
            for (int i = 0; i <= 5; i++)
            {
                Thread t = new Thread(Dotaskfunction);
                t.Start();
            }
            Console.WriteLine("Task   With Thread End !");
 
            Console.WriteLine("Task   With Task   Start !");
            for (int i = 0; i <= 5; i++)
            {
                Task.Run(() => { Dotaskfunction(); });
            }
            Console.WriteLine("Task   With Task End !");
            Console.ReadLine();
 
        }
 
        public static void Dotaskfunction()
        {
            Console.WriteLine("ThreadID: {0}", Thread.CurrentThread.ManagedThreadId);
 
        }
 
    }
}

2. 创建Task 

//方式1
//第一种创建方式,直接实例化:必须手动去Start   可以绑定有参数的委托对象
   var task1 = new Task(() =>
    {
       //TODO you code
    });
   task1.Start();
 
 
//方式2
//第二种创建方式,工厂创建,直接执行  且绑定的都是无参无返回值的委托对象
   var task2 = Task.Factory.StartNew(() =>
    {
     
    });
 
或者是
Task.Run(() =>{
 
});
三、Task的任务控制:Task比threadPool优点就是任务控制,很好的控制task的执行顺序,让多个task有序的执行
 
 
Task.Wait	task1.Wait();就是等待任务执行(task1)完成,task1的状态变为Completed。
Task.WaitAll	待所有的任务都执行完成:
Task.WaitAny	等待任何一个任务完成就继续向下执行
Task.ContinueWith	第一个Task完成后自动启动下一个Task,实现Task的延续
CancellationTokenSource	通过cancellation的tokens来取消一个Task。
 
  //task1.Wait();就是等待任务执行(task)完成
            Task task = Task.Run(() => {    
                
                Thread.Sleep(3000);
                Console.WriteLine("1"); 
            
            });
          等待任务执行(task)完成  后执行后续代码
            task.Wait();
            Task task1 = Task.Run(() => { Console.WriteLine("2"); });
            Task task2 = Task.Run(() => { Console.WriteLine("3"); });
            
         
 
            Console.WriteLine("All task finished!");
 
 
//Task.WaitAll	待所有的任务都执行完成
 Task task = Task.Run(() => {    
                
                Thread.Sleep(3000);
                Console.WriteLine("1"); 
            
            });
            Task task1 = Task.Run(() => { Console.WriteLine("2"); });
            Task task2 = Task.Run(() => { Console.WriteLine("3"); });
            Task.WaitAll(task, task1, task2);
             待所有的任务都执行完成 执行以下内容
            Console.WriteLine("All task finished!");
 
 
Task.WaitAny	等待任何一个任务完成就继续向下执行
 
  Task task = Task.Run(() => {    
                
                Thread.Sleep(3000);
                Console.WriteLine("1"); 
            
            });
       
            Task task1 = Task.Run(() => { Console.WriteLine("2"); });
            Task task2 = Task.Run(() => { Console.WriteLine("3"); });
            //等待其中任意一个任务完成后 执行后续代码
            Task.WaitAny(task, task1, task2);
 
            Console.WriteLine("All task finished!");
 
 
 
       Task.ContinueWith  线程延续  :如果线程中的结果 需要再后续使用 使用线程延续
 
           //线程延续1
 
            Task<int> task10 = Task<int>.Run(() =>
            {
                for (int i = 0; i < 5; i++)
                {
 
                    Thread.Sleep(1000);
                    Console.WriteLine(i);
                }
                return 30;
            });
 
            task10.ContinueWith(tas =>
               {
                   //tas 代表 Task<int> task10
                   //获取task10的返回值结果
                   Console.WriteLine("task10任务执行完毕");
                   Console.WriteLine(tas.Result);
 
               });
 
            Console.WriteLine("11");
 
 
          //  线程延续2
            Task task11 = Task.Run(() =>
            {
 
                Console.WriteLine("1");
 
            });
 
            var result = task11.ContinueWith<string>(tas =>
            {
 
                Console.WriteLine("2");
                Task task1 = Task.Run(() =>
                {
 
                    Console.WriteLine("3");
                });
                Console.WriteLine("4");
                return "This is task result!";
            });
 
 
            Console.WriteLine(result.Result);
            延续3
            Task<float> task12 = Task.Run(() =>
            {
                return 10.0f;
            });
            var task13 = task12.ContinueWith<int>(tas =>
             {
 
                 10.0f;
                 Console.WriteLine(tas.Result);
                 return (int)(tas.Result + 10);
             });
 
            Console.WriteLine(task13.Result);
 task线程取消 方法
 
static void Main(string[] args)
        {
           
            //1.初始化线程取消类
            var tokenSource = new CancellationTokenSource();
            //2.获取线程取消标记
            var token = tokenSource.Token;
            //3.开启task线程  并且绑定取消线程标记
            var task = Task.Run(() =>
            {
                for (var i = 0; i < 1000; i++)
                {
                    Thread.Sleep(1000);
                    //是否执行取消方法 如果取消  为true  反之为 false
                    if (token.IsCancellationRequested)
                    {
                        Console.WriteLine("Abort mission success!");
                        return;
                    }
                }
            }, token);
            //取消线程后回调方法
            token.Register(() =>
            {
                Console.WriteLine("Canceled");
            });
            Console.WriteLine("Press enter to cancel task...");
            Console.ReadKey();
            //取消线程方法
            tokenSource.Cancel();
            Console.ReadKey();
        }

异步侧重于任务的执行顺序,而多线程则是关于多个线程如何并发执行。应该说多线程是实现异步的常用手段,但不能说他们是一回事。即便是只有一个线程的情况下,我们仍然可以实现异步

异步和同步

异步:表示执行某项操作之后不等待操作结束,但可以在操作结束后收到通知

同步反之

1. net5.0推出了async/await    async/await特性是与Task紧密相关的

2.async 是“异步”的简写,sync 是“同步”的简写

 await 是 async wait 的简写。await 用于等待一个异步方法执行完成

           //如何通过使用async/await  完成异步编程
            //1. async 必须修饰方法  被修饰的方法 表示是一个异步方法

            //2.async 和await必须连用  如果不使用await 那么这个方法还是同步方法
            //3.async 描述的方法 的返回值类型必须是void 或者是task 或者task<T>
            //4.await 描述的也是方法 但是必须是使用线程(task)的方法
            //5.Async方法在执行的时候,开始是以同步的方式执行,直到遇到await关键字,
            //从await关键字开始,C#会另起一个线程执行 async方法之外的其他代码

不使用async/await 完成下载逻辑,则代码执行顺序时混乱的,不符合业务逻辑:
 
internal class Program
    {
        static void Main(string[] args)
        {
            DownloadHandle();
            Console.ReadLine();
        }
        /// <summary>
        /// 1. 通知用户下载开始
        /// 2. 提示下载完成
        /// 3. 开始下载
        /// </summary>
        public static void DownloadHandle()
        {
            Console.WriteLine("下载开始!->主线程ID:" + Thread.CurrentThread.ManagedThreadId);
            Download();
            Console.WriteLine("下载完成!->主线程ID:" + Thread.CurrentThread.ManagedThreadId);
 
        }
        /// <summary>
        /// 下载
        /// </summary>
        /// <returns></returns>
        public static Task Download()
        {
            return Task.Run(() =>
            {
                Console.WriteLine("下载线程ID:->" + Thread.CurrentThread.ManagedThreadId);
                Console.WriteLine("10%");
                Console.WriteLine("30%");
                Console.WriteLine("50%");
                Console.WriteLine("60%");
                Console.WriteLine("80%");
                Console.WriteLine("99%");
                Console.WriteLine("100%");
            });
        }
    }
使用async/await 完成下载逻辑,则代码执行顺序正常,符合业务逻辑:
 
 
 
 
internal class Program
    {
        static void Main(string[] args)
        {
            DownloadHandle();
            Console.ReadLine();
        }
        /// <summary>
        /// 模拟下载
        /// </summary>
        public static async void DownloadHandle()
        {
            Console.WriteLine("下载开始!->主线程ID:" + Thread.CurrentThread.ManagedThreadId);
            await Download();
            Console.WriteLine("下载完成!->主线程ID:" + Thread.CurrentThread.ManagedThreadId);
 
        }
        /// <summary>
        /// 下载
        /// </summary>
        /// <returns></returns>
        public static Task Download()
        {
            Console.WriteLine("下载线程ID:->" + Thread.CurrentThread.ManagedThreadId);
            Console.WriteLine("10%");
            Console.WriteLine("30%");
            Console.WriteLine("50%");
            Console.WriteLine("60%");
            Console.WriteLine("80%");
            Console.WriteLine("99%");
            Console.WriteLine("100%");
            return Task.CompletedTask;
        }
 
 

winform使用BeginInvoke 和await 完成数据加载(后续讲)

 //BeginInvoke
 
 private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            //接收缓冲区数据的字节数
            int size = serialPort1.BytesToRead;
            //动态创建数组接收数据
            byte[] buffer = new byte[size];
            //读取数据
            serialPort1.Read(buffer, 0, buffer.Length);
 
            string msg = Encoding.Default.GetString(buffer);
 
            //异步执行,
            //txtReceive.BeginInvoke(msgDelegate, msg);
            txtReceive.BeginInvoke(new Action<string>(str =>
            {
                txtReceive.Text = str;
            }), msg);
        }
 
 
 
 
 
 
 private async void serialPort1_DataReceived1(object sender, SerialDataReceivedEventArgs e)
        {
           
            //await异步执行
            var t = Task.Run(() =>
            {
                //接收缓冲区数据的字节数
                int size = serialPort1.BytesToRead;
                //动态创建数组接收数据
                byte[] buffer = new byte[size];
                //读取数据
                serialPort1.Read(buffer, 0, buffer.Length);
 
                string msg = Encoding.Default.GetString(buffer);
                return msg;
            });
            string str = await t;
            txtReceive.Text = str;
        }

  • 18
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值