多线程

  • 线程:进程中的指令执行的路径称为线程。据说具有多个同时执行执行路径的程序是多线程应用程序。

  • 应用程序的运行实例是一个过程。每个进程都有自己的内存地址空间,并在所有数据和该过程的指令中驻留。

调度类型:

先发制人:OS可以取消安排一个线程,即使它没有完成任务也是如此。

先发制人:操作系统无法在未完成时未被划分的线程。一个线程应该是选定本身应该完成其任务。

  • 计划基于线程的优先级完成。在处理器中执行具有最优先级的线程。如果具有相同优先级的多个线程,则将时间片分配给每个线程。

  • 在MS-Windows执行线程中基于:抢占计划 优先事项 Time slice

  • 此外,在所有版本的MS Windows中,为了避免饥饿低优先级线程也在处理器中执行,但它们执行的次数非常少。

  1. 跑步: 当它在执行其指令之一时,据说一个线程处于运行状态。

  2. 准备好: 线程正在等待分配处理器。这是运行状态的唯一入口点。当胎面未划分时,它从运行到就绪状态。

  3. 死的:执行线程中的所有指令后,它会变成死状态。无法复活死线程。

  4. 睡眠: 睡眠时,线程不会执行任何任务。一个线程自身睡觉状态,并且预定义的时间。一个睡眠线程 中断 throws “threadinterruptedException“。 当线程处于睡眠状态时,所有资源/锁都会阻止线程保持。

  5. 暂停: 线程可以暂停自己或另一个线程。悬挂线程本身无法恢复。线程可以暂停暂停状态以进行无限时间。

  6. 被封锁: 当资源无法使用时,据说一个线程在封锁状态下,它正在等待它们。一旦提供资源,线程会自动恢复。

  7. 等待: 在等待状态之前的线程释放其已阻止的资源/锁。只有另一个线程脉冲等待线程只能脉冲,然后它可以恢复并进入就绪状态。

在.NET中,每个线程都有两个与之关联的对象。

  1. 类型的对象 system.Threading.Threads. 它负责管理线程的生命周期和状态。

  2. A 自定义对象,它负责提供线程在其寿命期间必须管理的指令和数据。

例1:

使用系统;

使用system.threading;

班级演示

{

       公共字符串消息;

      公共INT间隔= 1000;

      public void 跑步()

     {

        for (int i = 0; i <5; I ++)//虽然(真)

      {

console.writeline(Thread.CurrentThread..姓名

+ ” : ” + Message);

      线程(间隔);

      }

   }

}

  • 演示类封装了 指示 线程 跑步 方法和封装 数据信息间隔 数据成员。

  • 当主线程终止时,该过程终止。

  • 仅当它创建的其他非背景线程终止时,线程才会终止。

  • 如果它必须终止,则创建者不会等待后台线程。

班级计划

{

静态void main(String [] args)

{

console.writeline(“Main method begins”);

     Demo d = new Demo();

    线程t =新线程(新        线Start.(d。跑步));

   t.姓名 = “T”;

  d.Message = “Hi”;

  d.Interval = 1000;

 t.开始();

 演示d1 =新演示();

  线程t1 =新线程(新   ThreadStart(d1.跑步));

  t1.姓名 = “T1”;

  d1.Message = “Hello”;

  d1.Interval = 2000;

  t1.开始();

  t.加入(2000);

  if (t.活着)

  Console.WriteLine(“t is alive”);

  t1.Join();

  //t1.是障碍 = t.isbackground = true;

console.writeline(“Main method ends”);

  }

}

T。join():如果线程执行t.join(),则将当前的线程状态更改为等待,并且仍然终止该状态,直到终止“T”的线程。

加入(3000) - 当前线程等待3000毫秒的最大值,然后将自动恢复。

T.Asalive() 检查线程是否已死亡或活跃..

thread.currentthread. :获取当前线程的引用。

T。线程提高 = threadPriority.highest。

T。abort(): 停止线程。当在它抛出的线程上调用abort()方法时 threadabortexception. 无论其国家如何。如果线程未处理此外,则终止此异常,如果它被处理,如果 thread.resetabort() 执行线程未中止并将继续正常执行。

T.IsBackground.:当一个线程被创建为后台线程时,Creator线程不等待后台线程终止或加入创建程序线程。当创建程序线程中止时,后台线程会自动中止。

例2: 程序在常规输入中打印“数据”,也可以通过从键盘读取其值来更改该数据。

类PrintThread.

{

   public string Data;

   public void Run()

  {

   while (true)

  {

  console.writeline(数据);

  Thread.Sleep(1000);

}

}

}

Class PrintProgram.

{

    公共静态void main()

   {

      printthread p = new printthread();

   线程t =新线程(新线程(p.run));

    t.Start();

   while (true)

   {

      Console.WriteLine(“请输入数据:“);

       p.data = console.readline();

   }

   }

}

例3: 展示线程的优先级

在处理器中调度的每个高优先级线程的每个周期的Windows操作系统中,一个单位升高了低优先级线程的优先级。这是这样做的,因此即使是那些优先级低的线程也有机会在处理器中执行以避免饥饿。

优先演示

课堂你好

{

    public long Counter;

    public void Run()

    {

       while(true)

        Counter++;

    }

}

注意:在双核处理器机器上,该程序应使用三个线程执行,因为处理器与其优先级同时执行两个线程。

类优先权分析

{

静态void main(String [] args)

{

你好 H1 = New Hello();

线程t1 =新线程(新线程(H1.Run));

hello h2 = new hello();

线程t2 =新线程(新线程(h2.run));

t1.优先事项 = 线程提高.超出正常水平;

t2.优先事项 = 线程提高.低于一般;

线。CurrentThread..优先事项 = 线程提高.最高;

t1.start(); t2.start();

thread.sleep(2000);

t1.abort(); t2.abort();

Double Pert1 = 100.0 * H1.Counter /(H1.Counter + H2.Counter);

Double Pert2 = 100.0 * H2.Counter /(H1.Counter + H2.Counter);

console.writeline(“T1 ” + perT1);

console.writeline(“T2 ” + perT2);

}

}

暂停恢复/睡眠 - 中断/中止演示

添加到项目新的Windows表单:( Demoform)

私人void run()

{

    int n = 0;

   while (true)

   {

     try

   {

            n++;

      lblcounter.text = n.tostring();

     Thread.Sleep(1000);

}

抓住 (threadabortexception. e)

{

      dialogresult dlgresult;

dlgresult = messagebox.show(“Are you sure?”,

“Abort”,messageboxbuttons.yesno);

如果(dlgresult == dialogresult.no)

线.resetabort.();

}

抓住 (threadinterruptedException. e)

{

                n = 0;

}

}

}

线程t;

私有void btnstart_click(...)

{

    t =新线程(新ThreadStart(运行));

    t.是障碍 = true;

    t.Start();

}

私有void btnabort_click(...)

{

          t.中止();

}

私有void btnsuspend_click(...)

{

           t.暂停();

}

私有void btnresume_click(...)

{

               t.恢复();

}

私有void btninterrupt_click(...)

{

                 t.打断();

}

私有void btnthreadstate_click(...)

{messagebox.show(t。线state..tostring());

}

// 以创建表单作为启动对象。

公共静态void main()

{

应用.跑步(新的demoform());

}

在项目属性中:更改 输出类型视窗 应用启动 目的去除造纸

线程同步

要求: 在某个对象由多个线程共享的情况下,如果线程必须修改对象的状态,则应确保在给定的时间内只有一个线程。

关键部分 是一块代码块,可以在任何给定的时间内仅由一个线程执行。

如果在同一共享对象上执行两个线程,则线程都可以在对象上执行某些方法在同一时间点,如果它们然后更改对象的状态,则可能导致导致线程去同步的数据的模糊性。为了避免我们使用 锁块.

在c#中

(ob)

{

}

在VB.

傻瓜 (ob)

结尾 傻瓜

.NET中的每个对象都有一种特殊类型的资源,称为 监视器。 试图进入的线程 块必须获取指定对象的监视器,只有它可以这样做,所以它将正在执行锁定的块其他明智之曲它必须等待监视器。

例子

班级分享

{

              int n;

             public int Incr()

             {

               lock (this)

              {

                  n++;

                 int k = 0;

为了 ( i = 0; i < 100000000; i++)

          k++;

          return n;

     }

    }

}

班级演示

{

          Shared s;

           公共演示(分享)

          {

             this.s = s;

            }

公共空白 run()

{

// (s) // 如果未编码demo.incr,则使用

// { 用于线程安全(没有锁定块)

console.writeline(s.Incr());

// }

}

}

类同步肿

{

公共静态void main()

{

           共享s =新共享();

           演示d1 =新演示;

           演示D2 =新演示;

          线程t1 =新线程(新线程(d1.run));

        线程t2 =新线程(新线程(d2.run));

         t1.start(); t2.start();

    }

}

  1. 线程安全课程: 当在同一时间使用多个线程时,不会检索其对象状态的类。

  2. 即使类不是线程安全(方法更改对象的状态没有锁定块内没有代码),我们仍然可以通过在同一对象上的锁块中调用所有方法来使其在多线程环境中使用其功能。

  3. 如果线程已获取对象的监视器,则它可以在不同对象的不同方法中输入任何数量的锁块。

  4. 锁定降级吞吐量I.e.生成输出的速率。

  5. 类的共享/静态成员可以通过获取锁定在其中同步它们中的代码 类型 那个类的实例。

mut

它是一个同步资源 由操作系统管理。因此它可以用于同步运行的线程 不同的过程.

注意:监视器是一个特定于.NET特定对象,并且是给定进程的本地,因此它不能用于同步运行在不同进程中的线程。

如果使用互斥锁必须同步两个或多个线程,则它们都应该引用 相同的 mut 目的 或者如果对象是不同的,那么所有互斥对象都必须具有 一样的名字 因此,所有互斥对象都指的是OS中相同的互斥资源。

适合():检查互斥锁的可用性。如果可用获取它并将继续执行其他当前线程状态已更改为等待互斥锁。

recesemutex.() - 释放互斥锁

mutex m =新互斥(false,“test”);

如果第一个参数为true,则创建互斥对象的第一个线程将是互斥锁的所有者。 FALSE将阻止线程对象获取互斥锁,直至执行waiteOne()方法。

“test”是OS中标识的互斥锁的名称。

例1

filestream fs;

streamwriter. sw;

mut m = 新的 mut(错误的, “M1”);

私人的 空白 btnOpenFile_Click(目的 发件人, eventargs. e)

{

BOOL. flag = m.WaitOne(0,错误的);

如果 (!flag)

{

信息Box.。展示(“文件已被另一个应用程序使用”);

   return;

}

FS = 新的 filestream(“c:\\mutexdemo.txt”, filemode.。创造);

SW = 新的 streamwriter.(FS);

btnopenfile.enabled =. 错误的;

btnclosefile.enabled = 真的;

btnwriteTofile.enabled =. 真的;

}

私人的 空白 btnCloseFile_Click(目的 发件人, eventargs. e)

{

SW.Close();

fs.close();

btnopenfile.enabled =. 真的;

btnclosefile.enabled = 错误的;

btnwriteTofile.enabled =. 错误的;

m.releasemutex();

}

私人的 空白 btnwriteTofile_click(目的 发件人, eventargs. e)

{

sw.write(txttext.text);

txttext.text =. “”;

}

民众 静态的 空白 Main()

{

应用。跑步(新的 mutdemoform());

}

例2:

只允许一次应用程序的实例一次运行。

民众 静态的 空白 Main()

{

mut m = 新的 mut(错误的, “M1”);

BOOL. FirstInstance = M.Waitone(0,真的);

如果 (firstInstance)

{

application.run(新 主要的形式());

m.releasemutex();

}

别的

信息Box..show(“实例已经运行”);

}

笔记:

使用Ctrl + F5来执行程序两次

信号

信号量用于同步线程(在不同的过程中,在不同的过程中),它与互斥锁定合作,但具有允许多个线程(但预先定义的计数)的设施同时执行给定块。

互斥锁可以被视为数= 1的信号量的特殊情况。

班级Demo1.

{

// 静态的 信号 s =新 信号(3,3);

信号 s =新 信号(3,3,“测试“);

公共空白 run()

{

console.writeline(thread.currentthread.name.

+ ” Started”);

        s.适合();

        Thread.Sleep(1000);

        s.释放();

console.writeline(thread.currentthread.name.

+ ” Ended”);

}

}

班级Semaphoreemo

{

公共静态void main()

{

为了(int i = 0;一世< 15; i++)

{

        Demo1 D = New Demo1();

           线程t =新线程(

         新的ThreadStart(D.Run));

          t.姓名 = “T” + i;

           t.Start();

}

console.writeline(“Main method ends”);

}

}