C#专题之线程

2024-06-26 1064阅读

5.1 资源访问冲突问题


internal class StateObject
{
    private int state = 5;
    public void ChangeState()
    {
        if (state == 5)
        {
            state++;
            Console.WriteLine("state: " + state + " 线程ID:" + Thread.CurrentThread.ManageThreadId);
        }
        state = 5;
    }
}
static void Main(string[] args)
{
    StateObject state = new StateObject();
    for (int i = 0; i  

解决——加锁

internal class StateObject
{
    private Object _lock = new Object();
    private int state = 5;
    public void ChangeState()
    {
        lock (_lock)
        {
            if (state == 5)
            {
                state++;
                Console.WriteLine("state: " + state + " 线程ID:" + Thread.CurrentThread.ManageThreadId);
            }
            state = 5;
        }
    }
}

异步委托的方式启动线程


static void Test()
{
    Console.WriteLine("Test Started");
    Console.WriteLine("Test Running");
    Thread.Sleep(3000);
    Console.WriteLine("Test Completed");
}
delegate void TestDelegate();
static void Main(string[] args)
{
    TestDelegate testDelegate = Test;
    testDelegate.BeginInvoke(null, null);
    Console.WtiteLine("Main Completed");
}

线程的优先级和线程的状态


线程的优先级

在 Thread 类中,可以设置 Priority​ 属性,以影响线程的基本优先级,Priority​ 属性是 ThreadPriority​ 枚举定义的一个值。定义的级别有:Highest​、AboveNormal​、Normal​、BelowNormal​ 和 Lowest​。

C#专题之线程
(图片来源网络,侵删)

线程的状态

  • 获取线程的状态(Running 还是 Unstarted…),当我们通过调用 Thread 对象的 Start() 方法,可以创建线程,但是调用了 Start()​ 方法之后,新线程不是马上进入 Running 状态,而是处于 Unstarted 状态,只有当操作系统的线程调度器选择了要运行的线程,这个线程的状态才会修改为 Running 状态。我们使用 Thread.Sleep()​ 方法可以让当前线程休眠进入 WaitSleepJoin 状态。
  • 使用 Thread对象的 Abort()​ 方法可以停止线程。调用这个方法,会在要终止的线程中抛出一个 ThreadAbortException​ 类型的异常,我们可以 try catch 这个异常,然后在线程终止前做一些清理的工作。
  • 如果需要等待线程的结束,可以调用 Thread 对象的 Join()​ 方法,表示把 Thread 加入进来,暂停当前线程,并把它设置为 WaitSleepJoin 状态,直到加入的线程完成为止。

    线程池


    static void Main(string[] args)
    {
        for (int i = 0; i  
    
    • 使用线程池启动的线程默认是后台线程
    • 如果进程的所有前台线程都结束了,所有的后台线程就会停止,不能把入池的线程改为前台线程。
    • 不能给入池的线程设置优先级或名称
    • 入池的线程只能用于时间较短的任务,如果线程要一直运行,就应该使用 Thread​ 类创建一个线程。

      死锁问题


      internal class StateObject
      {
          private Object _lock1 = new Object();
          private Object _lock2 = new Object();
        
          private int state1 = 5;
          private int state2 = 5;
        
          public void ChangeState()
          {
              Console.WriteLine(Thread.CurrentThread.ManageThreadId + "拿到了第1把锁");
              lock (_lock1)
              {
                   lock (_lock2)
                  {
                      Console.WriteLine(Thread.CurrentThread.ManageThreadId + "拿到了第2把锁");
                      if (state1 == 5)
                      {
                          state1++;
                          Console.WriteLine("state: " + state1 + " 线程ID:" + Thread.CurrentThread.ManageThreadId);
                      }
                      state1 = 5;
        
                      if (state2 == 5)
                      {
                          state2++;
                          Console.WriteLine("state: " + state2 + " 线程ID:" + Thread.CurrentThread.ManageThreadId);
                      }
                      state2 = 5;
                  }
              }
          }
          public void ChangeState()
          {
              lock (_lock2)
              {
                  Console.WriteLine(Thread.CurrentThread.ManageThreadId + "拿到了第2把锁");
                   lock (_lock1)
                  {
                      Console.WriteLine(Thread.CurrentThread.ManageThreadId + "拿到了第1把锁");
                      if (state1 == 5)
                      {
                          state1++;
                          Console.WriteLine("state: " + state1 + " 线程ID:" + Thread.CurrentThread.ManageThreadId);
                      }
                      state1 = 5;
        
                      if (state2 == 5)
                      {
                          state2++;
                          Console.WriteLine("state: " + state2 + " 线程ID:" + Thread.CurrentThread.ManageThreadId);
                      }
                      state2 = 5;
                  }
              }
          }
      }
      

      解决方法——规定相同的拿锁顺序

      internal class StateObject
      {
          private Object _lock1 = new Object();
          private Object _lock2 = new Object();
        
          private int state1 = 5;
          private int state2 = 5;
        
          public void ChangeState()
          {
              Console.WriteLine(Thread.CurrentThread.ManageThreadId + "拿到了第1把锁");
              lock (_lock1)
              {
                   lock (_lock2)
                  {
                      Console.WriteLine(Thread.CurrentThread.ManageThreadId + "拿到了第2把锁");
                      if (state1 == 5)
                      {
                          state1++;
                          Console.WriteLine("state: " + state1 + " 线程ID:" + Thread.CurrentThread.ManageThreadId);
                      }
                      state1 = 5;
        
                      if (state2 == 5)
                      {
                          state2++;
                          Console.WriteLine("state: " + state2 + " 线程ID:" + Thread.CurrentThread.ManageThreadId);
                      }
                      state2 = 5;
                  }
              }
          }
          public void ChangeState()
          {
              lock (_lock1)
              {
                  Console.WriteLine(Thread.CurrentThread.ManageThreadId + "拿到了第1把锁");
                   lock (_lock2)
                  {
                      Console.WriteLine(Thread.CurrentThread.ManageThreadId + "拿到了第2把锁");
                      if (state1 == 5)
                      {
                          state1++;
                          Console.WriteLine("state: " + state1 + " 线程ID:" + Thread.CurrentThread.ManageThreadId);
                      }
                      state1 = 5;
        
                      if (state2 == 5)
                      {
                          state2++;
                          Console.WriteLine("state: " + state2 + " 线程ID:" + Thread.CurrentThread.ManageThreadId);
                      }
                      state2 = 5;
                  }
              }
          }
      }
      

      使用Thread启动线程和传输数据


      启动线程

      static void Test()
      {
          Console.WriteLine("Test Started");
          Console.WriteLine("Test Running");
          Thread.Sleep(1000);
          Console.WriteLine("Test Completed");
      }
      static void Main(string[] args)
      {
          Thread t = new Thread(Test);
          t.Start();
          Console.WriteLine("Main Completed");
      }
      

      使用 Lambda 表达式:

      static void Main(string[] args)
      {
          Thread t = new Thread(() => Console.WriteLine("Child Thread: " + Thread.CurrentThread.ManageThreadId));
          t.Start();
          Console.WriteLine("Main Completed: " + Thread.CurrentThread.ManageThreadId);
      }
      

      使用匿名方法:

      static void Main(string[] args)
      {
          Thread t = new Thread(delegate () {
              Console.WriteLine("Child Thread: " + Thread.CurrentThread.ManageThreadId)
          });
          t.Start();
          Console.WriteLine("Main Completed: " + Thread.CurrentThread.ManageThreadId);
      }
      

      传递数据

      static void Download(Object x)
      {
          string str = o as string;
          Console.WriteLine(str);
      }
      static void Main(string[] args)
      {
          Thread t = new Thread(Download);
          t.Start("http://www.xxx.com");
      }
      

      ​Start()​ 方法只能接收无参的方法或只有一个参数的方法

      传递多个数据

      public struct Data
      {
          public string message;
          public int age;
      }
      static void Download(Object x)
      {
          Data data = (Data)o;
          Console.WriteLine(data.message);
          Console.WriteLine(data.age);
      }
      static void Main(string[] args)
      {
          Data data = new Data();
          data.message = "";
          data.age = 12;  
          Thread t = new Thread(Download);
          t.Start(data);
      }
      

      任务


      static void Main(string[] args)
      {
          TaskFactory tf = new TaskFactory();
          Task t = tf.StartNew(Test);
          Thread.Sleep(5000);
      }
      static void Test()
      {
          for (int i = 0; i  
      
      static void Main(string[] args)
      {
          Task t = new Task(Test);
          t.Start();
          Thread.Sleep(5000);
      }
      static void Test()
      {
          for (int i = 0; i  
      

      连续任务

      如果一个任务t1的执行是依赖于另一个任务t2的,那么就需要在这个任务t2执行完毕后才开始执行t1。这个时候我们就可以使用连续任务。

      static void FirstDownload()
      {
          Console.WriteLine("Downloading ...");
          Thread.Sleep(2000);
      }
      static void SecondAlert(Task t)
      {
          Console.WriteLine("下载完成!");
      }
      static void Main(string[] args)
      {
          Task t1 = new Task(FirstDownload);
          t1.ContinueWith(SecondAlert);
          t1.Start();
          Thread.Sleep(5000);
      }
      
      static void FirstDownload()
      {
          Console.WriteLine("Downloading ...");
          Thread.Sleep(2000);
      }
      static void SecondAlert(Task t)
      {
          Console.WriteLine("下载完成!");
      }
      static void Main(string[] args)
      {
          Task t1 = new Task(FirstDownload);
          Task t2 = t1.ContinueWith(SecondAlert);
          Task t3 = t2.ContinueWith(SecondAlert);
          t1.Start();
          Thread.Sleep(5000);
      
VPS购买请点击我

免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们,邮箱:ciyunidc@ciyunshuju.com。本站只作为美观性配图使用,无任何非法侵犯第三方意图,一切解释权归图片著作权方,本站不承担任何责任。如有恶意碰瓷者,必当奉陪到底严惩不贷!

目录[+]