C#中的System.Threading线程问题

c#中的System.Threading

在说C#中的System.Threading之前,先来简单说说Process, Thread, CPU, 和OS。

Process 和 Thread 的比较

  • Process(进程)
    Process是正在运行的应用程序的实例(executing instance)。比如我们双击Microsoft Word图标,就启动了一个Process。所以说,一台计算机上可以运行多个Process
  • Thread(线程)
    线程,有时被称为轻量级进程(Lightweight Process,LWP),是程序执行流的最小单元。
    线程是进程中的一个实体,是被系统独立调度和分派的基本单位。
    一个进程可以有很多线程,每条线程并行执行不同的任务,称为多线程(multi-threading)。

单核CPU的运行方式

  • 运行一个thread
    thread首先加载到RAM中
  • 通过bus转移到CPU的pipeline中(一个queue)
  • 指令集(instruction set)中的指令依此被执行
  • 运行多个threads
    比如,两个threads加载到RAM中
  • 此时,在CPU和RAM中多了一个scheduler,负责把thread转移到CPU的pipeline中,scheduler会在两个threads之间相互转换,分别给每个thread一定的time slice
  • 对于我们而言,当time slice足够小,看起来两个threads就像是同时多线程(Simultaneous multithreading)

发展

  • 伴随着Multi-task OS和Multi-thread Application的出现,CPU设计也开始适应这种需求,出现了:
    Hyper Threading
    Multi-Core CPU
    Multi CPU

C#中的 System.Threading 命名空间

  • 第一个例子,不使用System.Threading
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
// 第一个控制台程序
namespace LearnThread
{
    class Program
    {
        static void subTask()
        {
            for (int i = 0; i < 5; i++)
            {
                Console.WriteLine("subTask is running");
            }
        }
        static void Main(string[] args)
        {
            subTask();
            for (int i = 0; i < 5; i++ )
            {
                Console.WriteLine("main is running");
            }
            Console.ReadLine();
        }
    }
}
  • subTask运行结束之后才会运行main中的for循环,运行结果为
subTask is running
subTask is running
subTask is running
subTask is running
subTask is running
main is running
main is running
main is running
main is running
main is running
  • 第二个例子,使用System.Threading,建立一个新thread
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
// 第二个控制台程序
namespace LearnThread
{
    class Program
    {
        static void subTask()
        {
            for (int i = 0; i < 5; i++)
            {
                Console.WriteLine("subTask is running");
            }
        }
        static void Main(string[] args)
        {
            // create one thread
            Thread t = new Thread(new ThreadStart(subTask)); 
            // invoke this thread
            t.Start();
            for (int i = 0; i < 5; i++ )
            {
                Console.WriteLine("main is running");
            }
            Console.ReadLine();
        }
    }
}

在运行subTask这个thread的时候,并不是运行到结束再执行main中的for循环,而是交替执行,类似Simultaneous multithreading,运行结果为(结果随机)

subTask is running
main is running
main is running
subTask is running
subTask is running
main is running
subTask is running
subTask is running
main is running
main is running

可见,System.Threading命名空间中的Thread类可以帮助我们实现程序中的并行。

  • System.Threading.Thread类中常见的方法
    Thread.Start(): 启动线程的执行
    Thread.Suspend(): 挂起线程,或者如果线程已挂起,则不起作用;
    Thread.Resume(): 继续已挂起的线程
    Thread.Interrupt(): 中止处于 Wait或者Sleep或者Join 线程状态的线程
    Thread.Join(): 阻塞调用线程,直到某个线程终止时为止
    Thread.Sleep(): 将当前线程阻塞指定的毫秒数
    Thread.Abort(): 终止此线程的过程。如果线程已经在终止,则不能通过Thread.Start()来启动线程

Thread的两种类型

  • Foreground thread
    如果主程序结束了,foreground thread依然存在或者继续运行。正如下面的例子:
namespace LearnThread
{
    class Program
    {
        static void Main(string[] args)
        {
            // A thread will be created to run
            // function1 parallely
            Thread obj1 = new Thread(Function1);
            obj1.IsBackground = true;
            obj1.Start();

            // the control will come here and exit the main function
            Console.WriteLine("The main application has exited");
        }

        static void Function1()
        {
            Console.WriteLine("Function 1 entered");
            // wait here until the user put any input
            Console.ReadLine();
            Console.WriteLine("Function 1 is exited");
        }
    }
}

程序的运行结果为:

The main application has exited
Function 1 entered
hello
Function 1 exited
Press any key to continue . . . 

可见,虽然主程序结束了,foreground thread依然会等待用户输入,在用户输入hello之后,执行最后一句,退出

  • Background thread
    如果主程序结束了,background thread也随即结束。正如下面例子:
namespace LearnThread
{
    class Program
    {
        static void Main(string[] args)
        {
            // A thread will be created to run
            // function1 parallely
            Thread obj1 = new Thread(Function1);
            obj1.IsBackground = true;
            obj1.Start();

            // the control will come here and exit the main function
            Console.WriteLine("The main application has exited");
        }

        static void Function1()
        {
            Console.WriteLine("Function 1 entered");
            // wait here until the user put any input
            Console.ReadLine();
            Console.WriteLine("Function 1 is exited");
        }
    }
}

改程序的输出结果为:

The main application has exited
Function 1 entered
Press any key to continue . . . 

可见,主程序退出后,background thread也结束了,没有再等待用户输入

关于 Thread Safe Object

  • 在两个thread中运行下面的程序,如果我们不考虑thread safe的问题,程序会报错,因为会出现零作为除数的情况
Random o = new Random();
for (long i = 0; i < 10000; i++)
{
    Num1 = o.Next(1, 2);
    Num2 = o.Next(1, 2);
    int result = Num1/Num2;
    Num1 = 0;
    Num2 = 0;
}

在.NET中提供的解决方案:

Lock

Mutex

Semaphore

比如,使用lock修改后的程序

Random o = new Random();
for (long i = 0; i < 10000; i++)
{
    lock (this)
    {
        Num1 = o.Next(1, 2);
        Num2 = o.Next(1, 2);
        int result = Num1/Num2;
        Num1 = 0;
        Num2 = 0;
    }
}
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值