假设有这个一个COM,以下是他的接口:
public interface udfCOM
{
string Action1(string[] argv);
void Action2(string[] argv);
void Action3(string[] argv, ref string val1, ref string val2);
}udfCOM允许被创建N个实例,每个实例运行在一个线程里,这些线程可能会并发调用Action1、Action2等函数,Action1、Action2等函数每次运行时间都不长,最多的情况是200毫秒左右。函数Action1、Action2等每次被调用时都会访问同一个资源,而这个资源必须是独占的。这个COM内部已经使用了诸如WaitforSingleObject等方法对任务进行了队列,但可能是因为没处理好,并发线程比较多时还是经常发生多个线程同时抢占资源的情况。现在的情况是这样,我们没有权限去修改这个COM的内部实现,我考虑在ASP.NET中用线程池来替代COM的内部队列。我要同步调用并得到结果,而Action1等函数很多且参数又很复杂,等请问该怎么做?我已经参阅了vs.net 的帮助“ms-help://MS.VSCC.2003/MS.MSDNQTR.2003FEB.2052/cpguide/html/cpconthreadpooling.htm”,感觉我这里需要的回调函数很不好写。附:原来我在web form调用该COM的代码如下,注意,在调用COM之前我可能需要处理我的参数,而且我不希望我处理这些参数的过程也被队列起来:
public class WebForm1 : System.Web.UI.Page
{
private void Page_Load(object sender, System.EventArgs e)
{
udfCOM com1 = new udfClass();
string cmd = string.Empty;
string result1 = string.Empty;
string result2 = string.Empty; switch(cmd)
{
case "cmd1":
result2 = Function1();
result1 = com1.Action1(null);
break;
case "cmd2":
com1.Action2(null);
break;
case "cmd3":
result2 = Function1();
com1.Action3(null, ref result1, ref result2);
break;
default:
break;
} this.Response.Write(result1 + "\n<br>\n" + result2);
} private string Function1()
{
return null;
}
}
public interface udfCOM
{
string Action1(string[] argv);
void Action2(string[] argv);
void Action3(string[] argv, ref string val1, ref string val2);
}udfCOM允许被创建N个实例,每个实例运行在一个线程里,这些线程可能会并发调用Action1、Action2等函数,Action1、Action2等函数每次运行时间都不长,最多的情况是200毫秒左右。函数Action1、Action2等每次被调用时都会访问同一个资源,而这个资源必须是独占的。这个COM内部已经使用了诸如WaitforSingleObject等方法对任务进行了队列,但可能是因为没处理好,并发线程比较多时还是经常发生多个线程同时抢占资源的情况。现在的情况是这样,我们没有权限去修改这个COM的内部实现,我考虑在ASP.NET中用线程池来替代COM的内部队列。我要同步调用并得到结果,而Action1等函数很多且参数又很复杂,等请问该怎么做?我已经参阅了vs.net 的帮助“ms-help://MS.VSCC.2003/MS.MSDNQTR.2003FEB.2052/cpguide/html/cpconthreadpooling.htm”,感觉我这里需要的回调函数很不好写。附:原来我在web form调用该COM的代码如下,注意,在调用COM之前我可能需要处理我的参数,而且我不希望我处理这些参数的过程也被队列起来:
public class WebForm1 : System.Web.UI.Page
{
private void Page_Load(object sender, System.EventArgs e)
{
udfCOM com1 = new udfClass();
string cmd = string.Empty;
string result1 = string.Empty;
string result2 = string.Empty; switch(cmd)
{
case "cmd1":
result2 = Function1();
result1 = com1.Action1(null);
break;
case "cmd2":
com1.Action2(null);
break;
case "cmd3":
result2 = Function1();
com1.Action3(null, ref result1, ref result2);
break;
default:
break;
} this.Response.Write(result1 + "\n<br>\n" + result2);
} private string Function1()
{
return null;
}
}
这里只需要使用.NET提供的线程同步机制既可但问题是既然这里资源访问是互坼的,那为什么还要用多线程?我是说既然这里必须按照顺序访问,那程序为什么不设计为顺序执行的?
假设有10个web用户同时请求WebForm1,根据参数的不同有人会调用Action1、有人会调用Action2,他们都要得到运行结果。按理来讲,COM内部应该自己处理好队列的问题,二次开发程序员不用考虑并发的问题,但问题就是他没处理好。所以才需要在WebForm1的代码中对任务(调用COM的某一个有返回值的函数)进行队列,同一个时刻只能有一个人调用COM的某一个函数。
COM本身通过STA/MTA/TNA单元可以处理好自身的多线程的问题
但是对于COM之外的资源,COM组件本身是无法控制多线程访问的问题的。任何组件都是如此>>> 我不知道多个人并发请求一个web form时IIS是不是开了多个线程处理web form的运行
是如果是这样,那可以设置个全局同步锁,比如在页面的静态构造函数内写:Application["syncroot"] = new object();
然后:
lock(Application["syncroot"])
{
switch(cmd){...}
}
最好还是使用异步的策略,在ASP.NET页内,使用一个新的线程来做这些费时的操作
{
private static udfCOMClass m_udfInstance = new udfCOMClass(); public string Action1(string[] argv)
{
string result = string.Empty; lock(m_udfInstance)
{
result = m_udfInstance.Action1(argv);
} return result;
} public void Action2(string[] argv)
{
lock(m_udfInstance)
{
m_udfInstance.Action2(argv);
}
} public void Action3(string[] argv, ref string val1, ref string val2)
{
lock(m_udfInstance)
{
m_udfInstance.Action3(argv, ref val1, ref val2);
}
}
}这样用有一个前提,就是假定udfCOMClass访问的资源必须是独占的,这样的代码才有意义。
事实上我前面也是这么问的。但是实际上udfCOMClass访问的资源有时候可以几个线程并发访问,但是不能太多。udfCOMClass内部也是因为这个问题所以才没有处理好。我之所以想改用线程池或者其他的什么办法,是我以为采用这些办法如果能解决1个的问题,就能解决2个甚至更多的问题。MFC中除了WaitforSingleObject,不是还有WaitForMultipleObjects么,可我就是一时间找不到一个较好的办法来写代码。
无法理解,嗯
2. lock是互斥的,不能完全满足我限制并发线程的要求,例如我要控制并发数最多为2个。
3. lock降低了asp.net的性能,并且不能设置超时时间,只能依赖于asp.net的页面超时来提示超时。