您的位置:首页 > 其它

把遇到过的对.Net线程的一些问题和误解集中起来和大家分享,也希望大家能一起补充,热烈欢迎讨论(引)

2008-01-04 10:26 1021 查看
目录

基础篇

怎样创建一个线程
名为BeginXXX和EndXXX的方法是做什么用的
异步和多线程有什么关联

WinForm多线程编程篇

我的多线程WinForm程序老是抛出InvalidOperationException ,怎么解决?
Invoke,BeginInvoke干什么用的,内部是怎么实现的
每个线程都有消息队列吗?
为什么Winform不允许跨线程修改UI线程控件的值
有没有什么办法可以简化WinForm多线程的开发

线程池

线程池的作用是什么?
所有进程使用一个共享的线程池,还是每个进程使用独立的线程池?
为什么不要手动线程池设置最大值?
.Net线程池有什么不足?

同步

CLR怎样实现lock(obj)锁定?
WaitHandle是什么,他和他的派生类怎么使用
什么是用双锁实现Singleton,为什么要这样做,为什么有人说双锁检验是不安全的
互斥对象(Mutex)、事件(Event)对象与lock语句的比较

什么时候需要锁定

只有共享资源才需要锁定
把锁定交给数据库
了解你的程序是怎么运行的
业务逻辑对事务和线程安全的要求
计算一下冲突的可能性
请多使用lock,少用Mutex

Web和IIS

应用程序池,WebApplication,和线程池之间有什么关系
Web页面怎么调用异步WebService

[align=center]基础篇[/align]

怎样创建一个线程

我只简单列举几种常用的方法,详细可参考.Net多线程总结(一)

一)使用Thread类

ThreadStart threadStart=new ThreadStart(Calculate);//通过ThreadStart委托告诉子线程讲执行什么方法,这里执行一个计算圆周长的方法

Thread thread=new Thread(threadStart);

thread.Start(); //启动新线程

delegate double CalculateMethod(double Diameter); //申明一个委托,表明需要在子线程上执行的方法的函数签名

CalculateMethod calcMethod = new CalculateMethod(Calculate);//把委托和具体的方法关联起来

//此处开始异步执行,并且可以给出一个回调函数(如果不需要执行什么后续操作也可以不使用回调)

calcMethod.BeginInvoke(5, new AsyncCallback(TaskFinished), null);

//线程调用的函数,给出直径作为参数,计算周长

//线程完成之后回调的函数

三)使用ThreadPool.QueueworkItem

WaitCallback w = new WaitCallback(Calculate);

//下面启动四个线程,计算四个直径下的圆周长

ThreadPool.QueueUserWorkItem(w, 1.0);

ThreadPool.QueueUserWorkItem(w, 2.0);

ThreadPool.QueueUserWorkItem(w, 3.0);

ThreadPool.QueueUserWorkItem(w, 4.0);

public static void Calculate(double Diameter)

ThreadStart threadStart=new ThreadStart(Calculate);//通过ThreadStart委托告诉子线程讲执行什么方法

Thread thread=new Thread(threadStart);

thread.Start();

delegate void changeText(double result);

delegate void changeText(double result);

string readpath = "e:\\RHEL4-U4-i386-AS-disc1.iso";

string writepath = "e:\\kakakak.iso";

byte[] buffer = new byte[90000000];

//FileStream outputfs=new FileStream(writepath, FileMode.Create, FileAccess.Write, FileShare.None,256,true);

//Console.WriteLine("异步流");

//创建了一个同步的流

FileStream outputfs = File.OpenWrite(writepath);

Console.WriteLine("同步流");

//然后在写文件期间查看线程池的状况

ShowThreadDetail("初始状态");

FileStream fs = File.OpenRead(readpath);

fs.BeginRead(buffer, 0, 90000000, delegate(IAsyncResult o)

null);

Console.ReadLine();

public static void ShowThreadDetail(string caller)

object lockobj=new object();

}

这样做其实是为了提高效率,比起
public static MySingleton Instance{

get{

lock(_instance){

if(s_value==null){

_instance= new MySingleton();

}

}

前一种方法在instance创建的时候不需要用lock同步,从而增进了效率

在java中这种技巧被证明是不安全的详细见http://www.cs.umd.edu/~pugh/java/memoryModel/

但是在.Net下,这样的技巧是成立的,因为.Net使用了改进的内存模型

并且在.Net下,我们可以使用LazyInit来实现单件

private static readonly _instance=new MySingleton()

public static MySingleton Instance{

get{return _instance}

}

当第一此使用_instance时,CLR会生成这个对象,以后再访问这个字段,将会直接返回

互斥对象(Mutex),信号量(Semaphore),事件(Event)对象与lock语句的比较

首先这里所谓的事件对象不是System.Event,而是一种用于同步的内核机制

互斥对象和事件对象属于内核对象,利用内核对象进行线程同步,线程必须要在用户模式和内核模式间切换,所以一般效率很低,但利用互斥对象和事件对象这样的内核对象,可以在多个进程中的各个线程间进行同步。

lock或者Moniter是.net用一个特殊结构实现的,不涉及模式切换,也就是说工作在用户方式下,同步速度较快,但是不能跨进程同步

[align=center]什么时候需要锁定? [/align]
刚刚接触锁定的程序员往往觉得这个世界非常的危险,每个静态变量似乎都有可能产生竞争

首先锁定是解决竞争条件的,也就是多个线程同时访问某个资源,造成意想不到的结果,比如,最简单的情况,一个计数器,如果两个线程同时加一,后果就是损失了一个计数,但是频繁的锁定又可能带来性能上的消耗,还有最可怕的情况,死锁

到底什么情况下我们需要使用锁,什么情况下不用呢?

只有共享资源才需要锁定

首先,只有可以被多线程访问的共享资源才需要考虑锁定,比如静态变量,再比如某些缓存中的值,属于线程内部的变量不需要锁定

把锁定交给数据库

数据库除了存储数据之外,还有一个重要的用途就是同步,数据库本身用了一套复杂的机制来保证数据的可靠和一致性,这就为我们节省了很多的精力.保证了数据源头上的同步,我们多数的精力就可以集中在缓存等其他一些资源的同步访问上了

了解你的程序是怎么运行的

实际上在web开发中大多数逻辑都是在单个线程中展开的,无论asp.net还是php,一个请求都会在一个单独的线程中处理,其中的大部分变量都是属于这个线程的,根本没有必要考虑锁定,当然对于asp.net中的application对象中的数据,我们就要小心一些了

WinForm中凡是使用BeginInvoke和Invoke调用的方法也都不需要考虑同步,因为这用这两个方法调用的方法会在UI线程中执行,因此实际是同步的,所以如果调用的方法中存在某些静态变量,不需要考虑锁定

业务逻辑对事务和线程安全的要求

这条是最根本的东西,开发完全线程安全的程序是件很费时费力的事情,在电子商务等涉及金融系统的案例中,许多逻辑都必须严格的线程安全,所以我们不得不牺牲一些性能,和很多的开发时间来做这方面的工作,而一般的应用中,许多情况下虽然程序有竞争的危险,我们还是可以不使用锁定,比如有的时候计数器少一多一,对结果无伤大雅的情况下,我们就可以不用去管他

计算一下冲突的可能性

我以前曾经谈到过,架构不要过设计,其实在这里也一样,假如你的全局缓存里的某个值每天只有几百或者几千个访问,并且访问时间很短,并且分布均匀(实际上这是大多数的情况),那么冲突的可能性就非常的少,也许每500天才会出现一次或者更长,从7*24小时安全服务的角度来看,也完全符合要求,那么你还会为这样万分之一的可能性花80%的精力去设计吗?

请多使用lock,少用Mutex

如果你一定要使用锁定,请尽量不要使用内核模块的锁定机制,比如.net的Mutex,Semaphore,AutoResetEvent,ManuResetEvent,使用这样的机制涉及到了系统在用户模式和内核模式间的切换,所以性能差很多,但是他们的优点是可以跨进程同步线程,所以应该清楚的了解到他们的不同和适用范围

[align=center]Web和IIS[/align]
应用程序池,WebApplication,和线程池之间有什么关系

一个应用程序池是一个独立的进程,拥有一个线程池,应用程序池中可以有多个WebApplication,每个运行在一个单独的AppDomain中,这些WebApplication公用一个线程池

不同的AppDomain保证了每个WebApplication的静态变量不会互相干扰,不同的应用程序池保证了一个网站瘫痪,其他不同进程中的站点还能正常运行

下图说明了他们的关系

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐