C#多线程基础知识和小实践

源文来源 :http://www.cnblogs.com/jackson0714/p/5100372.html

一、多线程介绍

C#通过多线程支持并行执行的代码。一个线程是一个独立执行的路径,可以同时与其他线程一起运行。一个C#客户端程序(Console,WPF,Winows
Forms)开始于一个单独的线程,该线程由CLR和操作系统自动地创建,我们称它为主线程,而且可以通过创建附加的线程来实现多线程。

1.一个简单的栗子

class Program
 2 {
 3             static void Main(string[] args)
 4             {
 5                 Thread thread = new Thread(WriteY);//创建一个线程
 6                 thread.Start();//开始一个线程
 7     
 8                 for (int i = 0; i < 1000; i++)//主线程执行循环
 9                 {
10                     Console.Write("x");
11                 }
12     
13                 Console.ReadLine();
14             }
15             static void WriteY()
16             {
17                 for (int i = 0; i < 1000; i++)
18                 { 
19                     Console.Write("y"); 
20                 }
21             }
22 
23     }

在这里插入图片描述
一旦开始,一个线程的IsAlive属性返回true,直到这个线程结束。当传递给线程的构造函数的委托完成执行时,这个线程结束。一旦结束,这个线程不能重启。IsAlive:判断线程是否还活着

2.内存隔离

CLR给每个线程分配自己内存栈,因此局部变量可以保持分离。在下面例子中,我们定义了一个使用局部变量的方法,然后在主线程和子线程同时调用这个方法

class Program
{
    static void Main(string[] args)
    {
        new Thread(Go).Start();
        Go();
        Console.ReadKey();
    }

    static void Go()
    {
        for (int i = 0; i < 5; i++)
        {
            Console.Write("y");
        }
    }
}

运行结果:
在这里插入图片描述

3.数据共享

如果多个线程对同一个对象实例有相同的引用,这些线程就共享这个对象实例的数据。

class ThreadTest 
{
  static bool done;    // 静态字段在所有线程之间共享
 
  static void Main()
  {
    new Thread (Go).Start();
    Go();
  }
 
  static void Go()
  {
    if (!done)
     { 
     done = true;
      Console.WriteLine ("Done"); 
     }
  }
}

在这里插入图片描述

4.线程安全

上面两个例子展示了另外一个重要的概念:线程安全确实是不确定的:done可能被打印出两次(尽管是不太可能发生的)。当我们把Go方法中的语句的顺序交换下,打印出两次done的几率显著提升

class ThreadTest 
{
  static bool done;    // 静态字段在所有线程之间共享
 
  static void Main()
  {
    new Thread (Go).Start();
    Go();
  }
 
  static void Go()
  {
    if (!done)
     { 
       Console.WriteLine ("Done"); 
       done = true;
     }
  }
}

在这里插入图片描述
这个地方的问题是线程A在线程B设置done等于true之前进入if条件判断中,所有A有机会打印出"Done"。

改进方式: 当读\写一个公共字段时,获取一个独占锁(exclusive lock)。C#提供了关键字lock。

class Program
{
    static bool done = false;
    static readonly object locker = new object();
    static void Main(string[] args)
    {
        new Thread(Go).Start();
        Go();
        Console.ReadKey();
    }

    static void Go()
    {
        lock (locker)
        {
            if (!done)
            {
                Console.WriteLine("Done");
                done = true;
            }
        }
    }
}

在这里插入图片描述

当两个线程同时抢占一个锁时(在这个例子中,locker),一个线程等待,或者阻塞,知道这个锁释放。在这个例子中,这个锁保证一次只有一个线程可以进入代码的临界区域,然后“Done”只会被打印一次。代码在这种不确定的多线程背景下中被保护被叫做线程安全。

注意:在多线程中,共享数据是造成复杂原因的主要,而且会产生让人费解的错误。尽管很基本但还是要尽可能保持简单。
一个线程,当阻塞的时候,不占用CPU资源。

二、Join 和Sleep

1.Join

当程序运行时,启动了一个耗时较长的线程来打印数字,打印每个数字前要等待两秒。但我们在主程序中调用了t.Join方法,该方法允许我们等待直到线程t完成。当线程t完成 "时,主程序会继续运行。借助该技术可以实现在两个线程间同步执行步骤。第一个线程会等待另一个线程完成后再继续执行。第一个线程等待时是处于阻塞状态(正如暂停线程中调用 Thread.Sleep方法一样),。

 static void Main(string[] args)
        {
            Thread t = new Thread(Print);
            t.Start();
            t.Join();
            MainPrint();
        }
        static void MainPrint()
        {
            Console.WriteLine("主线程执行");
        }
        static void Print()
        {
            Console.WriteLine("线程执行");
        }

在这里插入图片描述
当使用了Join方法后,等待Print执行完毕后,才执行MainPrint

2.Sleep
Thread.Sleep暂停当前线程一段指定的时间:
Thread.Sleep(TimeSpan.FromHours(1));//sleep一个小时
Thread.Sleep(500);//sleep 500 微秒
当使用Sleep或Join暂停线程时,这个线程是阻塞的,不消耗CPU资源

 static void Main(string[] args)
        {
            Thread t = new Thread(Print);
            t.Start();
            Thread.Sleep(TimeSpan.FromSeconds(5));
            MainPrint();
        }
        static void MainPrint()
        {
            Console.WriteLine("主线程执行");
        }
        static void Print()
        {
            Console.WriteLine("线程执行");
        }

结果是Print先执行,5秒后,MainPrint才执行

Thread.Sleep(0)立即放弃这个线程的时间片,主动交出CPU给其他线程。Framework 4.0的新方法Thread.Yield()方法做同样的事,除了当它仅仅在同一个进程中时,才会放弃时间片。
Sleep(0)或Yield()有时候对提升产品性能有用。而且它们也是诊断工具可以帮助揭开线程安全的问题; 如果在代码中的任何地方都插入Thread.Yield(),会造成bug。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值