• 进程和线程详解


    概念:

    程序并不能单独运行。只有把程序装载到内存中,系统为它分配资源才能运行,进程就是执行程序的过程。程序和进程的区别是:程序是指令的集合,它是进程运行的静态描述文本;进程是程序的一次执行活动,是动态的。

    在多道编程中,我们允许多个程序同时加载到内存中,在操作系统的调度下,可以实现并发地执行。这样就大大提高了CPU的利用率。进程的出现让每个用户感觉到自己独享CPU,因此,进程就是为了在CPU上实现多道编程而提出的。

    情景假设:

    有一座工厂,时刻在运行。就像计算机的核心CPU,它承担了所有的计算任务。

    假定工厂的电力有限,一次只能供给一个车间使用。也就是说,一个车间开工的时候,其他车间都必须停工。背后的含义就是,单核CPU一次只能运行一个任务。

    进程就好比工厂的车间,它代表CPU所能处理的单个任务。任一时刻,CPU总是运行一个进程,其他进程处于非运行状态。

       【多进程进程并发】

    多进程其实是将所有进程按时间分为一个一个的时间片,每一个时刻只执行该运行的片,时间片过期后转而执行下一个进程的时间片。
    如下图:


    |~~~__~~~~~__~~~~~~~~~~~~~~~~ 进程A

    |__~~~~~~__~~~~~~~~~~~~~~~~~~ 进程B
    |
    |~~~~~__~~~~~~~__~~~~~~~~~~~~ 进程C
    |
    |______________________________时间轴

    从上图可以看出,进程B首先运行,然后当B运行结束后(时间片到)转到A,然后转到C
    不过由于时间片很短,所以看起来是并行处理的,其实不是,所以叫并发,而不是并行。
    其实每一个时间只运行一个进程的一片而已。


       【多进程并行】

    多核CPU同时运行多个程序。如下图:


    |cpu1______________________________ 进程A

    |cpu2______________________________ 进程B
    |
    |cpu3______________________________ 进程C
    |
    |__________________________________时间轴

     

    【进程调度算法】

    1.先来先服务调度算法。

    2.短作业(进程)优先调度算法。

    3.高优先权优先调度算法。

    4.时间片的轮转调度算法。

    5.多级反馈队列调度算法。

    (1) 应设置多个就绪队列,并为各个队列赋予不同的优先级。第一个队列的优先级最高,第二个队列次之,其余各队列的优先权逐个降低。

    (2) 当一个新进程进入内存后,首先将它放入第一队列的末尾,按FCFS原则排队等待调度。当轮到该进程执行时,如它能在该时间片内完成,便可准备撤离系统;如果它在一个时间片结束时尚未完成,调度程序便将该进程转入第二队列的末尾,再同样地按FCFS原则等待调度执行;如果它在第二队列中运行一个时间片后仍未完成,再依次将它放入第三队列,……,如此下去,当一个长作业(进程)从第一队列依次降到第n队列后,在第队列便采取按时间片轮转的方式运行。

    (3) 仅当第一队列空闲时,调度程序才调度第二队列中的进程运行;仅当第1~(i-1)队列均空时,才会调度第i队列中的进程运行。如果处理机正在第i队列中为某进程服务时,又有新进程进入优先权较高的队列(第1~(i-1)中的任何一个队列),则此时新进程将抢占正在运行进程的处理机,即由调度程序把正在运行的进程放回到第i队列的末尾,把处理机分配给新到的高优先权进程。

     

    只有一个车间主任(主线程)的车间只能在一个时间干一件事,如果想同时干两件事或多件事,就无能为力了。

    如果在车间主任工作的时候遇到阻塞,例如等待原料,工作就没办法进行下去了。

    【进程不足】

     1.只能在一个时间干一件事。

     2.进程遇到阻塞就会挂起。

    所以主任就招工人进来(多线程),一个车间里,可以有很多工人协同完成一个任务。

    【线程】

     线程就是进程中的一个基本执行单元。

     这里涉及到多任务操作系统的问题,多任务操作系统(如Windows)的基本原理是:操作系统将CPU的时间片分配给多个线程,每个线程在操作系统指定的时间片内完成(注意,这里的多个线程是分属于不同进程的).  操作系统不断的从一个线程的执行切换到另一个线程的执行,如此往复,宏观上看来,就好像是多个线程在一起执行.由于这多个线程分属于不同的进程,因此在我们看来,就好像是多个进程在同时执行,这样就实现了多任务。

    车间的空间是工人们共享的,比如许多房间是每个工人都可以进出的。这象征一个进程的内存空间是共享的,每个线程都可以使用这些共享内存。

    每间房间的大小不同,有些房间最多只能容纳一个人,比如厕所。里面有人的时候,其他人就不能进去了。这代表一个线程使用某些共享内存时,其他线程必须等它结束,才能使用这一块内存。

    【线程同步】

    当使用多个线程来访问同一个数据时,非常容易出现线程安全问题(比如多个线程都在操作同一数据导致数据不一致),所以我们用同步机制来解决这些问题。

    一个防止他人进入的简单方法,就是门口加一把锁。先到的人锁上门,后到的人看到上锁,就在门口排队,等锁打开再进去。这就叫"互斥锁"(Mutual exclusion,缩写 Mutex),防止多个线程同时读写某一块内存区域。

    【互斥锁】

     1 using System;
     2 using System.Collections.Generic;
     3 using System.Linq;
     4 using System.Text;
     5 using System.Threading;
     6 using System.Threading.Tasks;
     7 
     8 namespace TestThread
     9 {
    10     public class Program
    11     {
    12         static void Main(string[] args)
    13         {
    14             PrintNum pr = new PrintNum();
    15             for (int i = 1; i <= 5; i++)
    16             {
    17                 Thread thread = new Thread(new ParameterizedThreadStart(pr.work));
    18 
    19                 thread.Start(i);
    20             }
    21 
    22             Thread.Sleep(1000);
    23             Console.WriteLine("Main thread over!");
    24 
    25             Console.ReadLine();
    26         }
    27     }
    28 
    29     public class PrintNum
    30     {
    31         Mutex mu = new Mutex();
    32 
    33         public void work(object obj)
    34         {
    35 
    36             //mu.WaitOne();
    37 
    38             lock (this)
    39             {
    40                 Console.WriteLine("Thread {0} start!", obj);
    41                 for (int i = 0; i < 5; i++)
    42                 {
    43                     Console.Write("{0},", i);
    44                 }
    45             }
    46 
    47             //mu.ReleaseMutex();
    48 
    49             Console.WriteLine();
    50         }
    51     }
    52 }
    View Code

     【死锁】:线程A锁定资源1访问资源2,同时线程B锁定资源2访问资源1,相互等待。

     1 using System;
     2 using System.Threading;
     3 using System.Diagnostics;
     4 
     5 namespace ConsoleApplication1
     6 {
     7     class Print
     8     {
     9         public void PrintFuntion()
    10         {
    11             Console.WriteLine("PrintFuntion()被调用");
    12         }
    13     }
    14 
    15     class SampleThread
    16     {
    17         private Print s1;
    18         private Print s2;
    19 
    20         public SampleThread(Print s1, Print s2)
    21         {
    22             this.s1 = s1;
    23             this.s2 = s2;
    24         }
    25 
    26         public void Deadlock1()
    27         {
    28             int i = 0;
    29 
    30             while (true)
    31             {
    32                 lock (s1)
    33                 {
    34                     Console.WriteLine("{0}锁定S1",Thread.CurrentThread.Name);
    35 
    36                     lock (s2)
    37                     {
    38                         Console.WriteLine("{0}锁定S2", Thread.CurrentThread.Name);
    39                         i++;
    40                         s1.PrintFuntion();
    41                         s2.PrintFuntion();
    42 
    43                         Console.WriteLine("运行," + i);
    44                     }
    45                 }
    46             }
    47         }
    48 
    49         public void Deadlock2()
    50         {
    51             int i = 0;
    52 
    53             while (true)
    54             {
    55                 lock (s2)
    56                 {
    57                     Console.WriteLine("{0}锁定S2", Thread.CurrentThread.Name);
    58 
    59                     lock (s1)
    60                     {
    61                         Console.WriteLine("{0}锁定S1", Thread.CurrentThread.Name);
    62                         i++;
    63                         s1.PrintFuntion();
    64                         s2.PrintFuntion();
    65 
    66                         Console.WriteLine("运行," + i);
    67                     }
    68                 }
    69             }
    70         }
    71     }
    72 
    73     class Program
    74     {
    75         static void Main(string[] args)
    76         {
    77             Print state1 = new Print();
    78             Print state2 = new Print();
    79 
    80             SampleThread sample = new SampleThread(state1, state2);
    81 
    82             var th1 = new Thread(sample.Deadlock1);
    83             var th2 = new Thread(sample.Deadlock2);
    84 
    85             th1.Name = "线程1";
    86             th2.Name = "线程2";
    87             th1.Start();
    88             th2.Start();
    89         }
    90     }
    91 }  
    View Code

           解决:从一开始定义好锁定的顺序,或者为锁定定义超时时间。

    1 Monitor.Wait(s2, 2000);//设定lock超时时间
    View Code

    还有些房间,可以同时容纳n个人,比如厨房。也就是说,如果人数大于n,多出来的人只能在外面等着。这好比某些内存区域,只能供给固定数目的线程使用。这时的解决方法,就是在门口挂n把钥匙。进去的人就取一把钥匙,出来时再把钥匙挂回原处。后到的人发现钥匙架空了,就知道必须在门口排队等着了。这种做法叫做"信号量"(Semaphore),用来保证多个线程不会互相冲突。

    信号量

     1 using System;
     2 using System.Collections.Generic;
     3 using System.Diagnostics;
     4 using System.Linq;
     5 using System.Text;
     6 using System.Threading;
     7 using System.Threading.Tasks;
     8 
     9 namespace TestThread
    10 {
    11     class Program
    12     {
    13         static Semaphore semaphore = new Semaphore(0, 5);
    14 
    15         static void Main(string[] args)
    16         {
    17             for (int i = 1; i <= 5; i++)
    18             {
    19                 Thread thread = new Thread(new ParameterizedThreadStart(work));
    20 
    21                 thread.Start(i);
    22             }
    23 
    24             Thread.Sleep(1000);
    25             Console.WriteLine("Main thread over!");
    26 
    27             semaphore.Release(3);
    28 
    29             Console.ReadLine();
    30         }
    31 
    32         static void work(object obj)
    33         {
    34             semaphore.WaitOne();
    35 
    36             Console.WriteLine("Thread {0} start!", obj);
    37 
    38             Thread.Sleep(3000);
    39 
    40             semaphore.Release();
    41         }
    42     }
    43 }
    View Code

     

    多线程比单线程快吗?简单测试了一下:

     1 using System;
     2 using System.Collections.Generic;
     3 using System.Diagnostics;
     4 using System.Linq;
     5 using System.Text;
     6 using System.Threading;
     7 using System.Threading.Tasks;
     8 
     9 namespace TestThread
    10 {
    11     public class Program
    12     {
    13         static void Main(string[] args)
    14         {
    15             Stopwatch sw = new Stopwatch();
    16             Addnumber addnumber = new Addnumber();
    17 
    18             sw.Start();
    19 
    20             new Thread(new ThreadStart(addnumber.Add)).Start();
    21             new Thread(new ThreadStart(addnumber.Add)).Start();
    22             new Thread(new ThreadStart(addnumber.Add)).Start();
    23             new Thread(new ThreadStart(addnumber.Add)).Start();
    24             new Thread(new ThreadStart(addnumber.Add)).Start();
    25             new Thread(new ThreadStart(addnumber.Add)).Start();
    26 
    27             sw.Stop();
    28             Console.WriteLine("耗时{0}", sw.Elapsed);
    29 
    30             Console.ReadLine();
    31         }
    32 
    33         //static void Main(string[] args)
    34         //{
    35         //    Stopwatch sw = new Stopwatch();
    36         //    Addnumber addnumber = new Addnumber();
    37         //    int count = 1;
    38 
    39         //    sw.Start();
    40 
    41         //    for (int i = 0; i < 30; i++)
    42         //    {
    43         //        count += count;
    44         //    }
    45         //    Console.WriteLine(count);
    46 
    47         //    sw.Stop();
    48         //    Console.WriteLine("耗时{0}", sw.Elapsed);
    49 
    50         //    Console.ReadLine();
    51         //}
    52     }
    53 
    54     public class Addnumber
    55     {
    56         int count = 1;
    57 
    58         public void Add()
    59         {
    60             for (int i = 0; i < 5; i++)
    61             {
    62                 count += count;
    63             }
    64 
    65             Console.WriteLine(count);
    66         }
    67     }
    68 }
    View Code

    结果并不是预想的那样,反而是六条线程比单线程耗时更多。

    【结论】:

    线程本身由于创建和切换的开销,采用多线程不会提高程序的执行速度,反而会降低速度,但是多线程是为了更充分的利用计算机的资源。比如网络,IO,CPU。对于频繁IO操作的程序,多线程可以有效的并发。

    所以在实际的开发中对于性能优化的问题需要考虑到具体的场景来考虑是否使用多线程技术。

  • 相关阅读:
    一次硬盘安装debian的过程
    Java热替换
    Hibernate缓存
    Java消息机制
    Hibernate批量操作(一)
    SQLite与SQL差异
    tablelayout:fixed 在一些情况下 会导至width失效。
    heiht三种浏览器的写法
    [WebMethod(EnableSession = true)]
    10分钟学会基于ASP.NET的 JQuery实例 (转)
  • 原文地址:https://www.cnblogs.com/endlessdream/p/4652118.html
Copyright © 2020-2023  润新知