zoukankan      html  css  js  c++  java
  • 进程与线程详细解释

      进程(process)和线程(thread)是操作系统的基本概念,但是它们比较抽象,不容易掌握,最近,我读到一篇材料,发现了一个很好的类比,可以把它们解释的清晰易懂。为接下来学习多线程编程做准备

    一.CPU,进程与线程:

      计算机的核心是CPU,它承担了所有的计算任务。它就像一座工厂,时刻在运行。假定工厂的电力有限,一次只能供给一个车间使用。也就是说,一个车间开工的时候,其他的车间必须停工。背后的含义就是,单个CPU一次只能运行一个任务

      • 进程就好比工厂车间,它代表CPU所能处理的单个任务。任一时刻,CPU总是运行一个进程,其它进程处于非运行状态
      • 一个车间里,可以有很多工人。他们协同完成一个任务!(线程就好比车间里的工人。一个进程可以包括多个线程)
      • 车间里的空间是工人们共享的,比如许多房间是每个工人都可以进出的。这象征一个进程的内存空间是共享的,每个线程都可以使用这些共享内存
      • 可是每个房间的大小不同,有些房间最多只能容纳一个人,比如厕所。里面有人的时候,其他人就不能进去了。这代表一个线程使用某些共享内存时,其他线程必须等他结束,才能使用这一块内存
      • 一个防止他人进入的简单方法,就是门口加一把锁。先到的人锁上门,后到的人看到上锁,就在门口排队,等锁打开在进去。这就叫“互斥锁”(Mutual exclusion,缩写Mutex),防止多个线程同时读写某一块内存区域
      • 还有些房间,可以同时容纳n个人,比如厨房。也就是说,如果人数大于n,多出来的人只能在外面等着。这好比某些内存区域,只能供给固定数目的线程使用
        • 解决方法,就在门口挂n把锁。进去的人就取一把钥匙,出来时再把钥匙挂回原处。后到的人发现钥匙架空了,就知道必须在门口排队等着了。这种做法就叫“信号量”(Semaphore),用来保证多个线程不会互相冲突

    二.线程的参数传递:

      一个 exe 运行一次就会产生一个进程,一个进程里至少有一个线程:主线程。我们平时写的控制台程序默认就是单线程的,代码从上往下执行,一行执行完了再执行下一行

      • 线程先创建的线程,不一定最先执行(先创建的线程,最先执行的概率会更高点)
      • 哪个线程最先执行由操作系统调度

    1.没有进行参数传递:

    static void Main(string[] args)
    {
        int i = 5;
        Thread thread = new Thread(() =>
        {
            Console.WriteLine("i="+i);   //输出i=6,这里也有可能i=5,就是当i=6执行之前就执行了这段代码
        });
        thread.Start();
        i = 6;
        Console.ReadKey();  
    }

    2.参数传递:

    static void Main(string[] args)
    {
        int i = 5;
        Thread thread = new Thread((obj) =>
        {
            Console.WriteLine("i=" + obj);   //输出i=5,这里取的就是 thread.Start(i);i=5的值
        });
        thread.Start(i);
        i = 6;
        Console.ReadKey();  
    }

    三.线程的执行:

      线程默认是“非后台线程”,一个程序必须所有“非后台线程”执行结束后程序才会退出。

      把线程设置为“后台线程”后,所有“非后台线程”执行结束后程序就会退出,不会等后台线程”执行结束

       thread.IsBackground = true;           //设置为后台线程

       Thread.Sleep(1000)                       //让当前线程睡眠多长时间

    1.线程的优先级:

      thread.Priority = ThreadPriority.Normal;            //可以设置5个优先级,优先级高的被执行的次数会多的点,平时就设置一个Normal就可以了

    2.线程的终止:

       thread.Abort()                            //终止这个线程

       解析:

        会在当前执行的代码上“无风起浪”的抛出 ThreadAbortException。来终止当前线程的执行,在程序中,一般不需要捕获处理这个异常

    3.唤醒线程:

    static void Main(string[] args)
    {
        Thread thread1 = new Thread(() => {
            try
            {
                Thread.Sleep(5000);
            }
            catch (ThreadInterruptedException)
            {
                Console.WriteLine("唤醒了线程");
            }
        });
        thread1.Start();
        Console.ReadKey();
    }

        thread1.Interrupt();     //唤醒线程就会执行ThreadInterruptedException中catch的方法里面的唤醒方法

        Sleep 是静态方法,只能是自己主动要求睡,别人不能命令他睡

    四.线程同步:

       线程同步:就是解决多个线程同时操作一个资源的问题

        thread1.Join();                //代表等待thread1线程执行完毕

    示例代码:

     1 class Program
     2 {
     3     private static int count = 0;
     4     static void Main(string[] args)
     5     {
     6         Thread thread1 = new Thread(() => {
     7             for (int i = 0; i < 1000; i++)
     8             {
     9                 count++;
    10                 Thread.Sleep(1);
    11             }
    12             
    13         });
    14         Thread thread2 = new Thread(() => {
    15             for (int i = 0; i < 1000; i++)
    16             {
    17                 count++;
    18                 Thread.Sleep(1);
    19             }
    20         });
    21         thread1.Start();
    22         thread2.Start();
    23         thread1.Join();
    24         thread2.Join();
    25         Console.WriteLine(count);
    26         Console.ReadKey();
    27     }
    28 }
    每次执行结果可能都不一样

     解决多个线程同时操作一个资源:用lock加锁,锁定一个资源。同时只能有一个线程进入 lock 的对象的范围,其他 lock 的线程就要等待

    方法一:

     1 class Program
     2 {
     3     private static int count = 0;
     4     private static object locker = new object();
     5     static void Main(string[] args)
     6     {
     7         Thread thread1 = new Thread(() => {
     8             for (int i = 0; i < 1000; i++)
     9             {
    10                 lock (locker)
    11                 {
    12                     count++;
    13                 }
    14                 Thread.Sleep(1);
    15             }
    16             
    17         });
    18         Thread thread2 = new Thread(() => {
    19             for (int i = 0; i < 1000; i++)
    20             {
    21                 lock (locker)
    22                 {
    23                     count++;
    24                 }
    25                 Thread.Sleep(1);
    26             }
    27         });
    28         thread1.Start();
    29         thread2.Start();
    30         thread1.Join();
    31         thread2.Join();
    32         Console.WriteLine(count);
    33         Console.ReadKey();
    34     }
    35 }
    加锁处理后的代码,每次执行的结果就一样了

     方法二:

      方法上标注 [MethodImpl(MethodImplOptions.Synchronized)],这样一个方法只能同时被一个线程访问

    方法三:

       lock 关键字就是对 Monitor 的简化调用,lock 最终就编译成 Monitor

    static void QuQian(string name)
    {
        Monitor.Enter(locker);//等待没有人锁定 locker 对象,我就锁定它,然后继续执行
        try
        {
            Console.WriteLine(name + "查看一下余额" + money);
            int yue = money - 1;
            Console.WriteLine(name + "取钱");
            money = yue;//故意这样写,写成 money--其实就没问题
            Console.WriteLine(name + "取完了,剩" + money);
        }
        finally
        {
            Monitor.Exit(locker);//释放 locker 对象的锁
        }
    }            

        Monitor.TryEnter(locker)       //TryEnter 方法,如果 Enter 的时候有人在占用锁,它不会等待,而是会返回false

    五.WinForm中的多线程:

      使用 WebClient 获取一个网页然后显示到 WinForm 中,界面会卡。因为网络操作阻塞了主线程.对于比较耗时的操作,放到子线程中

    private void button1_Click(object sender, EventArgs e)
    {
        ThreadPool.QueueUserWorkItem(state=>{
            WebClient wc = new WebClient();
            string html= wc.DownloadString("https://github.com/");
            //TextBox.CheckForIllegalCrossThreadCalls = false;    不要使用这个
            this.BeginInvoke(new Action(()=>{
                textBox1.Text = html;
            }));
        });
    }
  • 相关阅读:
    希腊字母写法
    The ASP.NET MVC request processing line
    lambda aggregation
    UVA 10763 Foreign Exchange
    UVA 10624 Super Number
    UVA 10041 Vito's Family
    UVA 10340 All in All
    UVA 10026 Shoemaker's Problem
    HDU 3683 Gomoku
    UVA 11210 Chinese Mahjong
  • 原文地址:https://www.cnblogs.com/fengxuehuanlin/p/7546461.html
Copyright © 2011-2022 走看看