线程管理

线程管理现在变得越来越容易了。在.NET架构中,你可以从线程池中获取线程。线程池是一个生成线程的工厂,如果它已经生成了一定数量的线程且还没有被破坏的话,对它的调用会被阻止。但是,如何确保不会有太多的线程在规定时间内运行?毕竟,如果每个线程能够占用一个CPU核的100%,那么有超过CPU核数量的线程运行,只会导致操作系统启动线程时间分配,这将导致上下文切换和低效率运行。换句话说,同一核上的两个线程不会以两倍的时长完成,可能需要用两倍再加10 %左右的时间来完成。与一个线程相比较的话,三个线程在同一核上想占用100 %的CPU使用率可能会需要3.25——3.5倍的时长来完成。我的经验是,每个核都有多个线程试图占用100 %的CPU,但它们都不能达到目标。

所以,要怎样分配正在运行的线程数量呢?

有一个办法是在线程之间建立一个共享的旗语对象。在线程开始运行前,它会尝试调用旗语的WaitOne模式,并在完成后释放旗语。对CPU的核数量设置旗语限制,(使用EnvironmentProcessorCount功能限定);这将防止您的系统在同一时间运行的线程数多于核数量。与此同时,从线程池中拉出线程将确保您不会在同一时间创建过多线程。如果一次创建线程过多,即使他们并没运行,那也是浪费系统资源。因为每个线程都要消耗资源。使用旗语的一般模式如下所示:

以下为引用的内容:

   static Semaphore threadBlocker;

  static void Execute(object state)

  { threadBlocker.WaitOne(); //Do work threadBlocker.Release(); }

  static void RunThreads()

  { threadBlocker = new Semaphore(0, Environment.ProcessorCount); for (int x = 0; x <= 2000; x++) {ThreadPool.QueueUserWorkItem(new WaitCallback (Execute)); } }

当然还有其他一些办法可以解决这一问题。前一段时间我想要保持对象的一份〈T〉清单。每个对象代表每个工人部件的完整状态。执行和完成时,工人部件都会被填入数据。并且他会设置某个功能以指示任务完成。主线程将扫描对象清单,如果运行的线程数量足够少,就开始运行另一个。说实话,虽然这个方法可行,但对于代码和调试来说这绝对是个噩梦,所以我一点也不推荐。

数据完整性

总体而言,在数据完整性方面,你要担心的问题是竞争条件和死锁。多个线程试图在同一时间更新相同的对象就会造成竞争条件,这将招致麻烦。想象一下如果使用下面这段代码:

以下为引用的内容:

  int x = 5;

  x = x + 10;

现在,如果线程A和线程B在同一时间运行此代码,将会发生什么情况?它可以运行得很好?还是会出现什么问题?如果出现问题,又是些怎样的问题呢?每个线程都不会一次执行全部语句。因此,我们可以按照以下顺序操作:

以下为引用的内容:

  1. Thread A retrieves the value of x (5).

  2. Thread B retrieves the value of x (5).

  3. Thread A assigns x + 10 (15) to x.

  4. Thread B assigns x + 10 (15) to x.

  5. x is now equal to 15.

或者,相同的代码可以按照不同的顺序:

以下为引用的内容:

  1. Thread A retrieves the value of x (5).

  2. Thread A assigned x = 10 (15) to x.

  3. Thread B retrieves the value of x (15).

  4. Thread B assigns x + 10 (25) to x.

5. x is now equal to 25.

在.NET架构中,最简单也最常见的解决竞争条件的方法是使用“临界区”。而在VB.NET中,该语句是“加锁”,并在C#中是“锁定”,这两种语句都是把对象作为参数。其他尝试锁定相同对象实例使用的临界区(包括上文所指的)会阻止运行直到锁定解除,这样每次就只有一个临界区运行。我们先前举例的一段代码现在看起来是这样的:

以下为引用的内容:

  int x = 5;

  object lockObject = new object();

  Monitor.Enter(lockObject);

  x = x + 10;

  Monitor.Exit(lockObject);

什么是监控器可以提供而临界区做不到的呢?答案是没有。除非你在解锁后需要更细粒度的控制权。有些复杂的代码可能需要锁定或长或短的一段时间,这都取决于运行的情况,比方一个变量的值。在这种情况下,选择监控器要比需选择临界区更合适。

另一个值得关注的有关数据完整性的问题是死锁。当多个线程锁定资源导致它们都不能够继续运行时,就会出现死锁。例如:

以下为引用的内容:

  Thread A:
 
  Monitor.Enter(object1);

  Monitor.Enter(object2);

  //Do work

  Monitor.Exit(object1);

  Monitor.Exit(object2);

  Thread B:

  Monitor.Enter(object2);

  Monitor.Enter(object1);

  //Do work

  Monitor.Exit(object1);

  Monitor.Exit(object2);

如果线程A和线程B都调用它们的第一段语句并且同时完成运行,那它们都无法调用它们的第二段语句——这就是一个死锁。所以编写代码的时候细心,要仔细想清楚怎样编写代码才更有利。死锁的发生常见于新手,因为他们过分设置锁定把它变得太详细了。如果代码被嵌套锁定通常表明需要对编写的代码加以认真检查。

转载于:https://www.cnblogs.com/webnet/archive/2009/03/22/1419068.html

在.NET上执行多线程操作要考虑的两大因素相关推荐

  1. 直接在 DNA 上执行 SQL 操作,已通过 PostgreSQL 验证

    法国通信系统工程师学校与研究中心(Eurecom)数据科学系助理教授 Appuswamy 和伦敦帝国理工学院 SCALE 实验室负责人 Heinis 等人近期发表了一篇关于在 DBMS 存储层操作 D ...

  2. Java 8 如何以并发方式在同一个流 上执行多种操作

    Java 8 中,流有一个非常大的(也可能是最大的)局限性,使用时,对它操作一次仅能得到一个处理结果.实际操作中,如果你试图多次遍历同一个流,结果只有一个,那就是遭遇下面这样的异常: java.lan ...

  3. HTML5:插入视频及在视频层面上执行的操作

    DEMO:http://craftymind.com/factory/html5video/CanvasVideo.html   点击播放的视频将产生奇特的效果. 注:请使用FF及Chrome浏览器浏 ...

  4. BackgroundWorker 实现多线程操作

    背景介绍 在做程序的过程中,我们很可能遇到这样的情况:当我们执行一个比较耗时的操作,即界面加载数据量略大的时,在该操作未完成之前再去操作界面,就会出现停止响应的情况,这称为界面假死状态,那一个小圆圈转 ...

  5. vue.js crud_如何使用VS Code和ADO.NET使用ASP.NET Core执行CRUD操作

    vue.js crud 介绍 (Introduction) In this article we are going to create a web application using ASP.NET ...

  6. 离散结构和离散数学中文书_在离散数学中对场景执行的操作

    离散结构和离散数学中文书 Prerequisite: Set theory and types of set in Discrete Mathematics 先决条件: 离散数学中的集合论和集合类型 ...

  7. 如何在多个SQL Server上执行作业

    介绍 (Introduction) In earlier chapter, we explained how to run queries in multiple SQL servers using ...

  8. scala使用log4j_将Twitter4j与Scala结合使用以执行用户操作

    scala使用log4j 介绍 我以前的文章展示了如何在Scala中使用Twitter4j访问Twitter流 . 这篇文章展示了如何使用Twitter4j控制Twitter用户的操作. 此功能的主要 ...

  9. 将Twitter4j与Scala结合使用以执行用户操作

    介绍 我之前的文章展示了如何在Scala中使用Twitter4j访问Twitter流 . 这篇文章展示了如何使用Twitter4j控制Twitter用户的操作. 此功能的主要目的可能是为Twitter ...

  10. 【ketlle】本地开发kitlle job提交至linux生产环境上执行流程

    [ketlle]本地开发kitlle job提交至linux生产环境上执行 前言 操作步骤 后记 前言 因为kettle提供可视化界面,所以我们在本地开发的时候拖拽开发十分便捷,开发完成后,我们需要丢 ...

最新文章

  1. 微生物预测年龄,皮肤比肠道更准确
  2. 人工智能在未来将要经历的七个阶段
  3. linux 获取 基地址,linux - 每个函数加载的glibc基地址不同。 - SO中文参考 - www.soinside.com...
  4. Scala函数作为函数的返回值
  5. [转]终结PHP中文乱码的问题
  6. lisp用entmake生产圆柱体_使用lisp语言实现在平面图中自动画出桥梁的墩柱标识.doc...
  7. 艾特某人代码实现_Vue@某人,At某人,仿新浪微博@某人,@user,艾特,艾特某人...
  8. hapi和typescript构建项目(正在更新中)
  9. 1011. World Cup Betting (20)
  10. Tcl8.6原生支持oop了
  11. java des 0填充方式_DES填充方式与初始向量IV的作用
  12. 如何更好使用 ng-zorro-antd 图标
  13. Linux中断处理“下半部”机制
  14. 计算机主机电源品牌有哪些,电脑电源的一线品牌有哪些?
  15. oracle序列自增
  16. 精密电阻(1%) -- 贴片电阻常用标示方法(转载)
  17. 院校-美国:麻省理工学院(MIT)
  18. 【整理归纳】Linux中文件的Access,Modify,Change区别
  19. java 高并发商城库存订单处理,下单减库存,如何解决高并发减库存问题
  20. win10右键打不开显示设置和个性化的解决教程

热门文章

  1. rhel 5.3 nis 服务器搭建 详细(原创)
  2. 常用的一些注入命令!!!
  3. Keil/MDK(2):STM32堆栈使用情况分析
  4. 模板 - 数学 - 数论
  5. VS C#程序打包覆盖安装不能更新的解决方法
  6. mixins,generics(ApiView)
  7. mysql5.6源码自动安装脚本
  8. C语言精要总结-内存地址对齐与struct大小判断篇
  9. Impala 源码分析-FE
  10. PHP 判断字符的编码 并输出想要的编码格式字符 (转)