多线程

阅读 / 问答 / 标签

多线程中为什么要使用Dispatch

iOS中timer相关的延时调用,常见的有NSObject中的performSelector:withObject:afterDelay:这个方法在调用的时候会设置当前runloop中timer,还有一种延时,直接使用NSTimer来配置任务。 这两种方式都一个共同的前提,就是当前线程里面需要有一个...

countdownlatch 导致的多线程死锁

countdownlatch是通过计数器实现的,初始化时定义count数,每一个线程执行完将count数-1.当count=0时表示所以线程执行完毕,可以进入接下来的逻辑。 countdownlatch的await()方法是等待count=0,执行此方法时,执行完的线程会进入阻塞,并等待其他线程完成,当所有线程完成时,await会唤醒阻塞队列并释放所有线程资源。 当高并发请求时,countdownlatch的await方法有可能会引起死锁。如果使用的线程池数量较少,在高并发时会出现多个请求占用了全部的线程资源,但是每个请求又需要await其他线程,其他线程在等待线程池资源,导致多个请求同时进入线程阻塞,最后形成死锁。 解决方法,使用自定义线程池,扩大线程数量,并且建立线程池拒绝机制。

openGauss为什么要使用多线程架构?

随着计算机领域多核技术的发展,如何充分有效的利用多核的并行处理能力,是每个服务器端应用程序都必须考虑的问题。由于数据库服务器的服务进程或线程间存在着大量数据共享和同步,而多线程可以充分利用多CPU来并行执行多个强相关任务,例如执行引擎可以充分的利用线程的并发执行以提供性能。在多线程的架构下,数据共享的效率更高,能提高服务器访问的效率和性能,同时维护开销和复杂度更低,这对于提高数据库系统的并行处理能力非常重要。多线程的三大主要优势:优势一:线程启动开销远小于进程启动开销。与进程相比,它是一种非常“节俭”的多任务操作方式。在Linux系统下,启动一个新的进程必须分配给它独立的地址空间,建立众多的数据表来维护它的代码段、堆栈段和数据段,这是一种“昂贵”的多任务工作方式。而运行于一个进程中的多个线程,它们彼此之间使用相同的地址空间,共享大部分数据,启动一个线程所花费的空间远远小于启动一个进程所花费的空间。优势二:线程间方便的通信机制:对不同进程来说,它们具有独立的数据空间,要进行数据的传递只能通过通信的方式进行,这种方式不仅费时,而且很不方便。线程则不然,由于同一进程下的线程之间共享数据空间,所以一个线程的数据可以直接为其他线程所用,这不仅快捷,而且方便。优势三:线程切换开销小于进程切换开销,对于Linux系统来讲,进程切换分两步:1.切换页目录以使用新的地址空间;2.切换内核栈和硬件上下文。对线程切换,第1步是不需要做的,第2步是进程和线程都要做的,所以明显线程切换开销小。

arduino如何实现多线程?

Arduino只有一个CPU,要在一个CPU上实现多线程的话,最终都是通过软件实现的。Arduino是一款便捷灵活、方便上手的开源电子原型平台,包含硬件(各种型号的Arduino板)和软件(ArduinoIDE)。它构建于开放原始码simpleI/O介面版,并且具有使用类似Java、C语言的Processing/Wiring开发环境。看实际情况吧,如果只是差一个半个输入I/O,可以选用Nano板代替,比UNO多出两个analoginput。如果真的不够用,想要调用的库也不少了,也要考虑程式的空间是否足够。UNO只有32KBflash,Mega2560可是256KB。而SDRAMmega2560亦是UNO的4倍。对比较大的程式,mega是必然的。这些记忆体的限制,单靠扩展I/O是不行的。如果空间及预算许可的话,mgea2560硬体上也可以给更大的弹性,将来再增加设备也比较容易,而且有多个serialI/O及interrupt,可实现的东西更多。但mgea2560长一半,对细小系统来说会比较大了。所以,如果可以的话,个人觉得mega2560比UNO+扩展I/O更好。用微信控制灯泡。搞个微信公众号,设置把请求转发到你自己的公众号服务器。公众号服务器上用Python搭一个HTTP服务器,获取到来自微信的请求。然后用Python开多一个线程通过TCP/UDP协议把消息推送到本地电脑,电脑通过串口连接Arduino电路板。Python调用serial模块和Arduino电路板通信,Arduino控制灯泡的行为。实现了一下,写得很简陋:livoras/wx-arduino·GitHub要是你有兴趣,还可以把Arduino接入你的家用电路,脑洞大一点你就可以在公司用微信控制你家的空调。UPDATE:代码仓库已经没有维护了,哪位大神有兴趣可以把它弄成通用的流程和组件,说不定是个商机(逃

java多线程调用ktr文件内存溢出java.lang.OutOfMemoryError:GC overhead limit exceeded

两种方案:1.把Java虚拟机的内存设大点;2.手动释放内存机制,而不是执行完之后由Java虚拟机统一释放

Java多线程之Atomic:原子变量与原子类

   一 何谓Atomic?   Atomic一词跟原子有点关系 后者曾被人认为是最小物质的单位 计算机中的Atomic是指不能分割成若干部分的意思 如果一段代码被认为是Atomic 则表示这段代码在执行过程中 是不能被中断的 通常来说 原子指令由硬件提供 供软件来实现原子方法(某个线程进入该方法后 就不会被中断 直到其执行完成)   在x 平台上 CPU提供了在指令执行期间对总线加锁的手段 CPU芯片上有一条引线#HLOCK pin 如果汇编语言的程序中在一条指令前面加上前缀 LOCK 经过汇编以后的机器代码就使CPU在执行这条指令的时候把#HLOCK pin的电位拉低 持续到这条指令结束时放开 从而把总线锁住 这样同一总线上别的CPU就暂时不能通过总线访问内存了 保证了这条指令在多处理器环境中的原子性    二 ncurrent中的原子变量   无论是直接的还是间接的 几乎 ncurrent 包中的所有类都使用原子变量 而不使用同步 类似 ConcurrentLinkedQueue 的类也使用原子变量直接实现无等待算法 而类似 ConcurrentHashMap 的类使用 ReentrantLock 在需要时进行锁定 然后 ReentrantLock 使用原子变量来维护等待锁定的线程队列   如果没有 JDK 中的 JVM 改进 将无法构造这些类 这些改进暴露了(向类库 而不是用户类)接口来访问硬件级的同步原语 然后 ncurrent 中的原子变量类和其他类向用户类公开这些功能   ncurrent atomic的原子类   这个包里面提供了一组原子类 其基本的特性就是在多线程环境下 当有多个线程同时执行这些类的实例包含的方法时 具有排他性 即当某个线程进入方法 执行其中的指令时 不会被其他线程打断 而别的线程就像自旋锁一样 一直等到该方法执行完成 才由JVM从等待队列中选择一个另一个线程进入 这只是一种逻辑上的理解 实际上是借助硬件的相关指令来实现的 不会阻塞线程(或者说只是在硬件级别上阻塞了) 其中的类可以分成 组   AtomicBoolean AtomicInteger AtomicLong AtomicReference   AtomicIntegerArray AtomicLongArray   AtomicLongFieldUpdater AtomicIntegerFieldUpdater AtomicReferenceFieldUpdater   AtomicMarkableReference AtomicStampedReference AtomicReferenceArray   其中AtomicBoolean AtomicInteger AtomicLong AtomicReference是类似的   首先AtomicBoolean AtomicInteger AtomicLong AtomicReference内部api是类似的 举个AtomicReference的例子   使用AtomicReference创建线程安全的堆栈   Java代码   public class LinkedStack<T> {   private AtomicReference<Node<T》 stacks = new AtomicReference<Node<T》()   public T push(T e) {   Node<T> oldNode newNode;   while (true) { //这里的处理非常的特别 也是必须如此的   oldNode = stacks get()   newNode = new Node<T>(e oldNode)   if (pareAndSet(oldNode newNode)) {   return e;   }   }   }   public T pop() {   Node<T> oldNode newNode;   while (true) {   oldNode = stacks get()   newNode = oldNode next;   if (pareAndSet(oldNode newNode)) {   return oldNode object;   }   }   }   private static final class Node<T> {   private T object;   private Node<T> next;   private Node(T object Node<T> next) {   this object = object;   this next = next;   }   }   }   然后关注字段的原子更新   AtomicIntegerFieldUpdater<T>/AtomicLongFieldUpdater<T>/AtomicReferenceFieldUpdater<T V>是基于反射的原子更新字段的值   相应的API也是非常简   单的 但是也是有一些约束的   ( )字段必须是volatile类型的!volatile到底是个什么东西 请查看   ( )字段的描述类型(修饰符public/protected/default/private)是与调用者与操作对象字段的关系一致 也就是说调用者能够直接操作对象字段 那么就可以反射进行原子操作 但是对于父类的字段 子类是不能直接操作的 尽管子类可以访问父类的字段   ( )只能是实例变量 不能是类变量 也就是说不能加static关键字   ( )只能是可修改变量 不能使final变量 因为final的语义就是不可修改 实际上final的语义和volatile是有冲突的 这两个关键字不能同时存在   ( )对于AtomicIntegerFieldUpdater和AtomicLongFieldUpdater只能修改int/long类型的字段 不能修改其包装类型(Integer/Long) 如果要修改包装类型就需要使用AtomicReferenceFieldUpdater   在下面的例子中描述了操作的方法   [java]   import ncurrent atomic AtomicIntegerFieldUpdater;   public class AtomicIntegerFieldUpdaterDemo {   class DemoData{   public volatile int value = ;   volatile int value = ;   protected volatile int value = ;   private volatile int value = ;   }   AtomicIntegerFieldUpdater<DemoData> getUpdater(String fieldName) {   return AtomicIntegerFieldUpdater newUpdater(DemoData class fieldName)   }   void doit() {   DemoData data = new DemoData()   System out println( ==> +getUpdater( value ) getAndSet(data ))   System out println( ==> +getUpdater( value ) incrementAndGet(data))   System out println( ==> +getUpdater( value ) decrementAndGet(data))   System out println( true ==> +getUpdater( value ) pareAndSet(data ))   }   public static void main(String[] args) {   AtomicIntegerFieldUpdaterDemo demo = new AtomicIntegerFieldUpdaterDemo()   demo doit()   }   }   在上面的例子中DemoData的字段value /value 对于AtomicIntegerFieldUpdaterDemo类是不可见的 因此通过反射是不能直接修改其值的   AtomicMarkableReference类描述的一个<Object Boolean>的对 可以原子的修改Object或者Boolean的值 这种数据结构在一些缓存或者状态描述中比较有用 这种结构在单个或者同时修改Object/Boolean的时候能够有效的提高吞吐量   AtomicStampedReference类维护带有整数 标志 的对象引用 可以用原子方式对其进行更新 对比AtomicMarkableReference类的<Object Boolean> AtomicStampedReference维护的是一种类似<Object int>的数据结构 其实就是对对象(引用)的一个并发计数 但是与AtomicInteger不同的是 此数据结构可以携带一个对象引用(Object) 并且能够对此对象和计数同时进行原子操作   在本文结尾会提到 ABA问题 而AtomicMarkableReference/AtomicStampedReference在解决 ABA问题 上很有用    三 Atomic类的作用   使得让对单一数据的操作 实现了原子化   使用Atomic类构建复杂的 无需阻塞的代码   访问对 个或 个以上的atomic变量(或者对单个atomic变量进行 次或 次以上的操作)通常认为是需要同步的 以达到让这些操作能被作为一个原子单元    无锁定且无等待算法   基于 CAS (pare and swap)的并发算法称为 无锁定算法 因为线程不必再等待锁定(有时称为互斥或关键部分 这取决于线程平台的术语) 无论 CAS 操作成功还是失败 在任何一种情况中 它都在可预知的时间内完成 如果 CAS 失败 调用者可以重试 CAS 操作或采取其他适合的操作   如果每个线程在其他线程任意延迟(或甚至失败)时都将持续进行操作 就可以说该算法是 无等待的 与此形成对比的是 无锁定算法要求仅 某个线程总是执行操作 (无等待的另一种定义是保证每个线程在其有限的步骤中正确计算自己的操作 而不管其他线程的操作 计时 交叉或速度 这一限制可以是系统中线程数的函数 例如 如果有 个线程 每个线程都执行一次CasCounter increment() 操作 最坏的情况下 每个线程将必须重试最多九次 才能完成增加 )   再过去的 年里 人们已经对无等待且无锁定算法(也称为 无阻塞算法)进行了大量研究 许多人通用数据结构已经发现了无阻塞算法 无阻塞算法被广泛用于操作系统和 JVM 级别 进行诸如线程和进程调度等任务 虽然它们的实现比较复杂 但相对于基于锁定的备选算法 它们有许多优点 可以避免优先级倒置和死锁等危险 竞争比较便宜 协调发生在更细的粒度级别 允许更高程度的并行机制等等    常见的   非阻塞的计数器Counter   非阻塞堆栈ConcurrentStack lishixinzhi/Article/program/Java/gj/201311/27474

C语言 epoll和多线程有什么关系?

epoll处理并发事件,多线程处理并发业务

C语言 epoll和多线程有什么关系?

epoll是Linux内核为处理大批量文件描述符而作了改进的poll,是Linux下多路复用IO接口select/poll的增强版本,它能显著提高程序在大量并发连接中只有少量活跃的情况下的系统CPU利用率。另一点原因就是获取事件的时候,它无须遍历整个被侦听的描述符集,只要遍历那些被内核IO事件异步唤醒而加入Ready队列的描述符集合就行了。epoll除了提供select/poll那种IO事件的水平触发(LevelTriggered)外,还提供了边缘触发(EdgeTriggered),这就使得用户空间程序有可能缓存IO状态,减少epoll_wait/epoll_pwait的调用,提高应用程序效率。

iOS与多线程(十) —— NSThread的使用以及锁(一)

首先看下写作环境 NSThread 位于 Foundation 库中,是对 pthread 对象化的封装,首先看一下苹果给的API,后续会根据这些进行详细的说明。 这个是类可以直接访问的属性,使用的使用直接类方法调用就可以 [NSThread currentThread] 。 使用示例 用于判断是否是多线程 使用示例 下面看一下输出 每个线程都维护了一个键-值的字典,它可以在线程里面的任何地方被访问。你可以使用该字典来保存一些信息,这些信息在整个线程的执行过程中都保持不变。比如你可以使用它来存储在你的整个线程过程中 Run loop 里面多次迭代的状态信息。 使用示例 下面看一下输出 下面看一下线程优先级的设置 这里,iOS 8.0以后 threadPriority 已经被废弃了,用 qualityOfService 替换,这个是一个枚举,在线程start以后,就变为只读属性了。 使用示例 主线程名字默认为 main ,子线程如果不指定就为空。 使用示例 callStackReturnAddresses 线程的调用都会有函数的调用函数的调用就会有栈返回地址的记录,在这里返回的是函 数调用返回的虚拟地址,说白了就是在该线程中函数调用的虚拟地址的数组。 使用示例 同上面的方法一样,只不过返回的是该线程调用函数的名字数字。 使用示例 isMainThread 用来判断该线程是否是主线程,而 mainThread 用来获取当前的主线程。 使用示例 对象方法创建 下面看一下线程的初始化 类方法创建 下面就是使用示例 下面是输出 隐式创建 下面就是线程的状态控制 isExecuting 判断线程是否正在执行, isFinished 判断线程是否已经结束, isCancelled 判断线程是否撤销。 这个是线程的入口函数。 在程序运行过程中,如果存在多线程,那么各个线程读写资源就会存在先后、同时读写资源的操作,因为是在不同线程,CPU调度过程中我们无法保证哪个线程会先读写资源,哪个线程后读写资源。因此为了防止数据读写混乱和错误的发生,我们要将线程在读写数据时加锁,这样就能保证操作同一个数据对象的线程只有一个,当这个线程执行完成之后解锁。 常用的锁有下面几种 下面就是一个卖票的示例,用来说明互斥锁的作用 下面看一下输出 首先看一下API 下面我们换成NSLock看一下 接着看一下输出 NSConditionLock 用于需要根据一定条件满足后进行 加锁/解锁. 首先看下API 下面就看一下适用场景 此锁可以在同一线程中多次被使用,但要保证加锁与解锁使用平衡,多用于递归函数,防止死锁。 首先看下API文档 下面看这个示例,其实就是递归使用这个锁 看一下输出 前面四种都是互斥锁,这里和自旋锁有什么区别和联系呢? 共同点 不同点

VB.NET多线程应用

开发者一直要求微软为VB加入更多的多线程功能,对于也是这样。VB6已经支持建立多线程的EXE、DLL和OCX。不过使用多线程这个词语,可能也不太确切。因此VB6仅支持运行多个单线程的单元。一个单元实际上是代码执行的空间,而单元的边界限制了代码访问任何单元以外的事物。就不同了,它支持建立自由线程(free-threaded)的应用。这意味着多个线程可以访问同样一套的共享数据。本文的以下部分将讨论一下多线程的一些基本点。问题虽然VB6支持多个单线程的单元,不过它并不支持一个自由线程的模型,即不允许多个线程使用同一套数据。在许多的情况下,你需要建立一个新的线程来进行后台的处理,这样可提高应用的可用性,否则,一个长的处理就可以令程序的响应变得很慢,例如你按下表格上的一个取消按钮,却很久都没有响应。解决办法由于使用了CLR(Common Language Runtime),从而拥有了许多的新特性,其中的一个是可以创建自由线程的应用。使用线程在中,运用线程是很简单的。我们将在后面涉及其中的细节,现在我们首先来创建一个简单的表格,它使用一个新的线程来运行一个后台处理。第一件要做的事情是创建运行在新线程上的后台任务。以下的代码执行一个相当长的运行处理--一个无限的循环:Private Sub BackgroundProcess()Dim i As Integer = 1Do While TrueListBox1.Items.Add("Iterations: " + i)i += 1LoopEnd Sub这段代码无限地循环,并且在每次执行时为表格上的一个列表框加入一个项目。如果你对不熟悉的话,你将会发现这段代码和VB6的有一些区别:. 在声明变量Dim i As Integer = 1时赋值. 使用+=操作符i += 1代替i = i + 1. 没有使用Call关键字一旦我们拥有了一个工作的处理,我们就需要将这段代码分配给一个线程处理,并且启动它。为此我们要使用线程对象(Thread object),它是.NET架构类中System.Threading命名空间的一部分。在实例化一个新的线程类时,我们将要在线程类构造器执行的代码块的一个引用传送给它。以下的代码创建一个新的线程对象,并且将BackgroundProcess的一个引用传送给它:Dim t As Threadt = New Thread(AddressOf Me.BackgroundProcess)t.Start()AddressOf操作符创建了一个到BackgroundProcess方法的委派对象。在中,一个委派是一个类型安全、面向对象的函数指针。在实例化该线程后,你可以通过调用线程的Start()方法来开始执行代码。控制线程在线程启动后,你可以通过线程对象的一个方法来控制它的状态。你可以通过调用Thread.Sleep方法来暂停一个线程的执行,这个方法可以接收一个整型值,用来决定线程休眠的时间。拿前面的例子来说,如果你想让列表项目增加的速度变慢,可以在其中放入一个sleep方法的调用:Private Sub BackgroundProcess()Dim i As Integer = 1Do While TrueListBox1.Items.Add("Iterations: " + i)i += 1Thread.CurrentThread.Sleep(2000)LoopEnd SubCurrentThread是一个public static的属性值,可让你得到当前运行线程的一个引用。你还可以通过调用Thread.Sleep (System.Threading.Timeout.Infinite)来让线程进入休眠状态,有点特别的是,这个调用的休眠时间是不确定的。要中断这个休眠,你可以调用Thread.Interrupt方法。与休眠和中断类似的是挂起和恢复。挂起可让你暂停一个线程,直到另一个线程调用Thread.Resume为止。休眠和挂起的区别是,后者并不立刻让线程进入一个等待的状态,线程并不会挂起,直到.NET runtime认为现在已经是一个安全的地方来挂起它了,而休眠则会立刻让线程进入一个等待的状态。最后要介绍的是Thread.Abort,它会停止一个线程的执行。在我们的那个简单例子中,如果要加入一个按钮来停止处理,很简单,我们只要调用Thread.Abort方法就行了,如下所示:Private Sub Button2_Click(ByVal sender As System.Object, _ByVal e As System.EventArgs) Handles Button2.Clickt.Abort()End Sub这就是多线程的强大之处。用户界面的响应很好,因为它运行在一个单独的线程中,而后台的处理运行在另外一个线程中。在用户按下取消按钮时,便会马上得到响应,并且停止处理。上面的例子只是一个相当简单的应用。在编程时,你还需要使用到多线程的许多复杂特性。其中的一个问题是如何将程序的数据由线程类的构造器传入或者传出,也就是说,对于放到另外一个线程中的过程,你既不能传参数给它,也不能由它返回值。这是由于你传入到线程构造器的过程是不能拥有任何的参数或者返回值的。为了解决这个问题,可以将你的过程封装到一个类中,这样方法的参数就可使用类中的字段。这里我们举一个简单的例子,如果我们要计算一个数的平方,即:Function Square(ByVal Value As Double) As DoubleReturn Value * ValueEnd Function为了在一个新的线程中使用这个过程,我们将它封装到一个类中:Public Class SquareClassPublic Value As DoublePublic Square As DoublePublic Sub CalcSquare()Square = Value * ValueEnd SubEnd Class使用这些代码来在一个新的线程上启动CalcSquare过程,如下所示:Private Sub Button1_Click(ByVal sender As System.Object, _ByVal e As System.EventArgs) Handles Button1.ClickDim oSquare As New SquareClass()t = New Thread(AddressOf oSquare.CalcSquare)oSquare.Value = 30t.Start()End Sub要注意到,在线程启动后,我们并没有检查类中的square值,因为即使你调用了线程的start方法,也不能确保其中的方法马上执行完。要从另一个线程中得到值,有几个方法,这里使用的方法是最简单的,即是在线程完成的时候触发一个事件。我们将在后面的线程同步中讨论另一个方法。以下的代码为SquareClass加入了事件声明。Public Class SquareClassPublic Value As DoublePublic Square As DoublePublic Event ThreadComplete(ByVal Square As Double)Public Sub CalcSquare()Square = Value * ValueRaiseEvent ThreadComplete(Square)End SubEnd Class在调用代码中捕捉事件的方法和VB6差不多,你仍然要声明WithEvents变量,并且在一个过程中处理事件。有些不同的是,你声明处理事件的过程使用的是Handles关键字,而不是通过VB6中通常使用的Object_Event。Dim WithEvents oSquare As SquareClassPrivate Sub Button1_Click(ByVal sender As System.Object, _ByVal e As System.EventArgs) Handles Button1.ClickoSquare = New SquareClass()t = New Thread(AddressOf oSquare.CalcSquare)oSquare.Value = 30t.Start()End SubSub SquareEventHandler(ByVal Square As Double) _Handles oSquare.ThreadCompleteMsgBox("The square is "Square)End Sub对于这种方法,要注意的是处理事件的过程,在这个例子中的是SquareEventHandler,将运行在产生该事件的线程中。它并不是运行在表格执行的线程中。同步线程在线程的同步方面,提供了几个方法。在上面的平方例子中,你要与执行计算的线程同步,以便等待它执行完并且得到结果。另一个例子是,如果你在其它线程中排序一个数组,那么在使用该数组前,你必须等待该处理完成。为了进行这些同步,提供了SyncLock声明和Thread.Join方法。SyncLock可得到一个对象引用的唯一锁,只要将该对象传送给SyncLock就行了。通过得到这个唯一锁,你可以确保多个线程不会访问共享的数据或者在多个线程上执行的代码。要得到一个锁,可使用一个较为便利的对象--与每个类关联的System.Type对象。System.Type对象可通过使用GetType方法得到:Public Sub CalcSquare()SyncLock GetType(SquareClass)Square = Value * ValueEnd SyncLockEnd Sub另一个是Thread.Join方法,它可让你等待一个特定的时间,直到一个线程完成。如果该线程在你指定的时间前完成了,Thread.Join将返回True,否则它返回False。在平方的例子中,如果你不想使用触发事件的方法,你可以调用Thread.Join的方法来决定计算是否完成了。代码如下所示:Private Sub Button1_Click(ByVal sender As System.Object, _ByVal e As System.EventArgs) Handles Button1.ClickDim oSquare As New SquareClass()t = New Thread(AddressOf oSquare.CalcSquare)oSquare.Value = 30t.Start()If t.Join(500) ThenMsgBox(oSquare.Square)End IfEnd Sub对于这种方法,要注意的是处理事件的过程,在这个例子中的是SquareEventHandler,将运行在产生该事件的线程中。它并不是运行在表格执行的线程中。

net 中多线程有几种实现方法

1:UI线程。这个线程是操作系统自动创建的,你画了个winform,那么程序一启动,自然有了这么个线程。值得注意的是,你添加一个Timer控件,现实的多线程,实际上,依然在UI线程里。只是定时被Timer夺去控制权而已,本质上依然是单线程。另一个线索也可以论证:本来非UI线程想更新UI界面,是需要利用delegate,involk等来实现的,但是在timer控件的线程里,是不需要的。2:Thread thread = new Thread(obj.functionName); thread.start();这样自定义的线程是真正的多线程,它的使用也是最灵活的。不像Timer线程,精确度只有50ms。值得注意的是:如果需要启动的线程函数是带输入参数的,怎么办?有两个办法:A:你不是启动obj对象里的函数吗?在thread.start();之前,你先添加这句话 MyObject obj = new MyObject(int a ,int b); 这样,obj.functionName函数里可以直接使用a和b了。还有个方法,就是利用委托封装函数,然后thread.start(参数);具体代码如下:[ComVisibleAttribute(false)]public delegate void ParameterizedThreadStart(Object obj)//这个Thread类的构造方法的定义如下:public Thread(ParameterizedThreadStart start);public static void myStaticParamThreadMethod(Object obj){ Console.WriteLine(obj);}static void Main(string[] args){ Thread thread = new Thread(myStaticParamThreadMethod); thread.Start("通过委托的参数传值");}3:利用threadpool线程池技术。threadpool的主要原理是池里面的线程不会完成一个任务就消亡,而是会继续执行其他的任务,这减少了线程的消亡和生成的代价。主要是ThreadPool.QueueUserWorkItem()和ThreadPool.RegisterWaitForSingleObject(···)两个静态函数。具体如下:QueueUserWorkItem的使用:static void ThreadProc(Object stateInfo) { Console.WriteLine("Hello from the thread pool."); }Main函数里ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadProc)); 即可。(注意WaitCallback系统委托),它的功能就像第2种方法里提到的new thread。那么RegisterWaitForSingleObject是干什么的呢?这个方法的做用是向线程池添加一个可以定时执行的方法。有点像第一种方法里提到的timer线程,却不属于UI线程。具体的使用如下:AutoResetEvent wait = new AutoResetEvent(false);object state = new object();ThreadPool.RegisterWaitForSingleObject(wait, new WaitOrTimerCallback(test), state, 5000, false);//5000是间隔调用的时间,也就是wait变量卡住的timeout时间(我觉得内部是这样实现的)wait.Set(); //如果有set这句话,那么第一次执行不用等5秒,则直接执行目标函数,否则没这句话,第一次执行要等5秒的。还有一个要注意:我平常使用的是ManualResetEvent,但在threadpool里,首先要选的是AutoResetEvent,因为AutoResetEvent能自动reset,所以下一次间隔来了,又要重新等待5秒钟,达到定时器的目的。如果是ManualResetEvent,要么一次执行不了(初始值为false),要么不间断的玩命执行。ManualResetEvent和AutoResetEvent的另一个重要区别是前者能一次唤醒多个线程,而后者一次只能唤醒一个线程。其实RegisterWaitForSingleObject函数的使用有点想我封装好的MyTimer类的实现了:我里面的while死循环里用了个wait.waitone(2000,false);即可。对了,说到这里,RegisterWaitForSingleObject函数实现的定时器,如果手动停止呢?这要用到Unregister函数:RegisteredWaitHandle rw = ThreadPool.RegisterWaitForSingleObject(wait, new WaitOrTimerCallback(test), state, 3000, false);rw.Unregister(wait);嗯讨论了这么多线程的东西,干脆再说一个小点:Thread.IsBackground=true的时候,指示该线程为后台线程。后台线程将会随着主线程的退出而退出

net 中多线程有几种实现方法?

1:UI线程。这个线程是操作系统自动创建的,你画了个winform,那么程序一启动,自然有了这么个线程。值得注意的是,你添加一个Timer控件,现实的多线程,实际上,依然在UI线程里。只是定时被Timer夺去控制权而已,本质上依然是单线程。另一个线索也可以论证:本来非UI线程想更新UI界面,是需要利用delegate,involk等来实现的,但是在timer控件的线程里,是不需要的。x0dx0a2:Thread thread = new Thread(obj.functionName); thread.start();x0dx0a这样自定义的线程是真正的多线程,它的使用也是最灵活的。不像Timer线程,精确度只有50ms。值得注意的是:如果需要启动的线程函数是带输入参数的,怎么办?x0dx0a有两个办法:x0dx0aA:你不是启动obj对象里的函数吗?在thread.start();之前,你先添加这句话 MyObject obj = new MyObject(int a ,int b); 这样,obj.functionName函数里可以直接使用a和b了。还有个方法,就是利用委托封装函数,然后thread.start(参数);具体代码如下:x0dx0ax0dx0a[ComVisibleAttribute(false)]x0dx0apublic delegate void ParameterizedThreadStart(Object obj)x0dx0a//这个Thread类的构造方法的定义如下:x0dx0apublic Thread(ParameterizedThreadStart start);x0dx0ax0dx0apublic static void myStaticParamThreadMethod(Object obj)x0dx0a{x0dx0a Console.WriteLine(obj);x0dx0a}x0dx0a x0dx0astatic void Main(string[] args)x0dx0a{x0dx0a Thread thread = new Thread(myStaticParamThreadMethod);x0dx0a thread.Start("通过委托的参数传值");x0dx0a}x0dx0ax0dx0a3:利用threadpool线程池技术。threadpool的主要原理是池里面的线程不会完成一个任务就消亡,而是会继续执行其他的任务,这减少了线程的消亡和生成的代价。x0dx0a主要是ThreadPool.QueueUserWorkItem()和ThreadPool.RegisterWaitForSingleObject(···)两个静态函数。具体如下:x0dx0aQueueUserWorkItem的使用:x0dx0astatic void ThreadProc(Object stateInfo)x0dx0a {x0dx0a Console.WriteLine("Hello from the thread pool.");x0dx0a }x0dx0aMain函数里ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadProc)); 即可。(注意WaitCallback系统委托),它的功能就像第2种方法里提到的new thread。x0dx0a那么RegisterWaitForSingleObject是干什么的呢?这个方法的做用是向线程池添加一个可以定时执行的方法。有点像第一种方法里提到的timer线程,却不属于UI线程。x0dx0a具体的使用如下:x0dx0aAutoResetEvent wait = new AutoResetEvent(false);x0dx0aobject state = new object();x0dx0aThreadPool.RegisterWaitForSingleObject(wait, new WaitOrTimerCallback(test), state, 5000, false);x0dx0a//5000是间隔调用的时间,也就是wait变量卡住的timeout时间(我觉得内部是这样实现的)x0dx0await.Set(); //如果有set这句话,那么第一次执行不用等5秒,则直接执行目标函数,否则没这句话,第一次执行要等5秒的。x0dx0a还有一个要注意:我平常使用的是ManualResetEvent,但在threadpool里,首先要选的是AutoResetEvent,因为AutoResetEvent能自动reset,所以下一次间隔来了,又要重新等待5秒钟,达到定时器的目的。如果是ManualResetEvent,要么一次执行不了(初始值为false),要么不间断的玩命执行。x0dx0aManualResetEvent和AutoResetEvent的另一个重要区别是前者能一次唤醒多个线程,而后者一次只能唤醒一个线程。x0dx0a其实RegisterWaitForSingleObject函数的使用有点想我封装好的MyTimer类的实现了:我里面的while死循环里用了个wait.waitone(2000,false);即可。x0dx0a对了,说到这里,RegisterWaitForSingleObject函数实现的定时器,如果手动停止呢?x0dx0a这要用到Unregister函数:x0dx0aRegisteredWaitHandle rw = ThreadPool.RegisterWaitForSingleObject(wait, new WaitOrTimerCallback(test), state, 3000, false);x0dx0arw.Unregister(wait);x0dx0ax0dx0a嗯讨论了这么多线程的东西,干脆再说一个小点:Thread.IsBackground=true的时候,指示该线程为后台线程。后台线程将会随着主线程的退出而退出

VB.NET 多线程下载遇到问题

定义委托 New Threading.Thread(AddressOf sDownFile)时,无法给Private Sub sDownFile(ByVal sURL As String, ByVal sFile As String)中的ByVal sURL As String, ByVal sFile As String传值
 首页 上一页  1 2