Interop的多线程并发 [英] Multithreading concurrency with Interop

查看:56
本文介绍了Interop的多线程并发的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

嘿所有。

我有一个遗留的COM dll,我想在我的多线程C#

app中使用。问题是,当我创建互操作对象的几个实例并在他们自己的线程上启动时,它们似乎总是同步运行




我把代码简化为一个简单的实验室。实验如下。在这个

控制台应用程序中,你会看到实例一在大约4

秒之后回来,然后实例2在8秒内回来,是时间的两倍。 />
这表示它在第一个线程上等待完成。为什么

不会同时运行?


我已经尽力确保线程类型是MTAThread

在调用COM对象之前。另外,在VB中,我确保项目

线程模型是Apartment Threaded。和Instancing设置为

GlobalUseMulti。


任何想法???

谢谢


******************* .NET C#CONSOLE TEST APP ********************

使用System;

使用System.Threading;


namespace ComThreadTest

{

class MyConsoleApp

{

[MTAThread]

static void Main(string [] args)

{

TestClass test1 = new TestClass(" 1");

TestClass test2 = new TestClass(" 2")


线程th =新线程(新的ThreadStart(test1.Go));

th.ApartmentState = ApartmentState.MTA;

th.Start();


th = new Thread(新的ThreadStart(test2.Go));

th.ApartmentState = ApartmentState.MTA;

th。开始();

}

}


公共类TestClass

{

public DotNetSleeperClass dotnet;

public MyCom.SleeperClass com;

pu blic string mName;


public TestClass(s​​tring name)

{

mName = name;

dotnet = new DotNetSleeperClass();

com = new MyCom.SleeperClass();

}


[MTAThread]

public void Go()

{

DateTime start = DateTime.Now;

Console.WriteLine(mName + " OUT在 +

start.ToString(" hh:mm:ss:fff"));


//这项工作很精细,因为它管理得很简单代码。

//dotnet.Go();


//这可以阻止其他线程运行com.Go();


DateTime finish = DateTime.Now;

TimeSpan ts =完成 - 开始;

Console.WriteLine(mName +" IN at" +

finish.ToString(" hh:mm:ss:fff")+" ELAPSED =" +

ts.TotalMilliseconds.ToString()+"毫秒。;;

Console.WriteLine(按任意键继续......);

Console.Read();

}

}


公共类DotNetSleeperClass

{

public DotNetSleeperClass(){ }


public void Go()

{

Thread.Sleep(3000);

}

}


}

******************* VB6 ACTIVEX DLL ********************

选项明确

公开Sub Go()

''在我的盒子上运行大约4秒钟。

Dim a,b,c

= 1到1000

对于b = 1到1000

c = a Mod b

DoEvents

下一个b

下一个

结束子

Hey all.
I''ve got a legacy COM dll that I''d like to use in my multithreaded C#
app. Problem though is when I create several instances of the interop
object and start them on their own threads they always seem to run
synchronously.

I''ve boiled down the code to a simple "lab" experiment below. In this
console app you''ll see that instance one comes back after roughly 4
seconds and then instance two comes back in 8 seconds, twice the time.
This indicates that it is wait on the first thread to finish. Why
won''t they run concurrently?

I''ve tried my best to make sure that the thread types are MTAThread
before calling the COM objects. Also, in VB I made sure the project
threading model was "Apartment Threaded" and the Instancing set to
GlobalUseMulti.

Any ideas???
Thanks

******************* .NET C# CONSOLE TEST APP ********************
using System;
using System.Threading;

namespace ComThreadTest
{
class MyConsoleApp
{
[MTAThread]
static void Main(string[] args)
{
TestClass test1 = new TestClass("1");
TestClass test2 = new TestClass("2");

Thread th = new Thread(new ThreadStart(test1.Go));
th.ApartmentState = ApartmentState.MTA;
th.Start();

th = new Thread(new ThreadStart(test2.Go));
th.ApartmentState = ApartmentState.MTA;
th.Start();
}
}

public class TestClass
{
public DotNetSleeperClass dotnet;
public MyCom.SleeperClass com;
public string mName;

public TestClass(string name)
{
mName = name;
dotnet = new DotNetSleeperClass();
com = new MyCom.SleeperClass();
}

[MTAThread]
public void Go()
{
DateTime start = DateTime.Now;
Console.WriteLine(mName + " OUT at " +
start.ToString("hh:mm:ss:fff"));

//THIS WORK FINE BECAUSE IT''S SIMPLE MANAGED CODE.
//dotnet.Go();

//THIS BLOCKS OTHER THREADS WHILE IT RUNS com.Go();

DateTime finish = DateTime.Now;
TimeSpan ts = finish - start;
Console.WriteLine(mName + " IN at " +
finish.ToString("hh:mm:ss:fff") + " ELAPSED=" +
ts.TotalMilliseconds.ToString() + " milliseconds.");
Console.WriteLine("Press any key to continue...");
Console.Read();
}
}

public class DotNetSleeperClass
{
public DotNetSleeperClass() {}

public void Go()
{
Thread.Sleep(3000);
}
}

}
******************* VB6 ACTIVEX DLL ********************
Option Explicit
Public Sub Go()
''On my box this runs in about 4 seconds to run.
Dim a, b, c
For a = 1 To 1000
For b = 1 To 1000
c = a Mod b
DoEvents
Next b
Next a
End Sub

推荐答案

如果你在单一过程中运行它或者有时甚至是一个双处理器,你不会在这些线程上看到并发性。处理器是
,允许第一个线程在上下文切换到新的
线程之前完成。在一个单一的机器上看到多线程操作的唯一真正的方法就是让线程跳进等待状态,而不是在做什么?
任何东西。然后你会看到你的其他线程在运行。

-

Justin Rogers

DigiTec Web Consultants,LLC。


" Mark Sisson" <毫安** @ corporatedigital.com>在留言中写道

news:88 ************************** @ posting.google.c om ...
If you are running this on a single-proc or sometimes even a dual-proc
machine you wouldn''t see concurrency on these threads. The processor is
allowing the first thread to finish before it does a context switch to a new
thread. The only real way to see multi-threading in action on a single-proc
machine is to have the thread jump into the wait state while it isn''t doing
anything. Then you''ll see your other threads running.
--
Justin Rogers
DigiTec Web Consultants, LLC.

"Mark Sisson" <ma**@corporatedigital.com> wrote in message
news:88**************************@posting.google.c om...
嘿所有。
我有一个遗留的COM dll,我想在我的多线程C#
应用程序中使用。问题是,当我创建互操作对象的几个实例并在他们自己的线程上启动它们时,它们似乎总是同步运行。

我已经将代码归结为代码简单的实验室实验如下。在这个
控制台应用程序中,你会看到实例一在大约4
秒后返回,然后实例2在8秒内返回,两倍的时间。
这表明它正在等待在第一个线程完成。为什么
不会同时运行?

在调用COM对象之前,我已经尽力确保线程类型是MTAThread
。此外,在VB中,我确保项目的线程模型是Apartment Threaded。和Instancing设置为GlobalUseMulti。

任何想法???
谢谢

************* ****** .NET C#CONSOLE TEST APP ********************
使用System;
使用System.Threading;

命名空间ComThreadTest
{MyconsoleApp类
{MTAThread]
static void Main(string [] args)
{<测试类test1 =新的TestClass(1);
TestClass test2 = new TestClass(" 2")

线程th =新线程(新的ThreadStart(test1。) Go));
th.ApartmentState = ApartmentState.MTA;
th.Start();

th = new Thread(new ThreadStart(test2.Go));
th.ApartmentState = ApartmentState.MTA;
th.Start();
}

公共类TestClass
{
public DotNetSleeperClass dotnet;
public MyCom.SleeperClass com;
public string mName;

public TestClass(s​​tring name)
{
mName = name;
dotnet = new DotNetSleeperClass();
com = new MyCom.SleeperClass();
}

[MTAThread]
public void Go()
{DateTime start = DateTime.Now;
Console.WriteLine(mName +" OUT在 +
start.ToString(" hh:mm:ss:fff"));

//这项工作很精细,因为它是简单的管理代码。
// dotnet.Go();

//当它运行时阻止其他线程com.Go();

DateTime finish = DateTime.Now;
TimeSpan ts =完成 - 开始;
Console.WriteLine(mName +" IN at" +
finish.ToString(" hh:mm:ss:fff")+" ELAPSED =" +
ts.TotalMilliseconds.ToString()+毫秒。;
Console.WriteLine(按任意键继续......);
Console.Read() ;
}

公共类DotNetSleeperClass
公共DotNetSleeperClass(){}

public void Go()
{
Thread.Sleep(3000);
}
}

}

******* ************ VB6 ACTIVEX DLL ********************
选项明确
Public Sub Go()
''在我的盒子上运行大约4秒钟。
昏暗a,b,c
对于a = 1到1000
对于b = 1到1000
c = a Mod b
DoEvents
下一步b
下一页
End Sub
Hey all.
I''ve got a legacy COM dll that I''d like to use in my multithreaded C#
app. Problem though is when I create several instances of the interop
object and start them on their own threads they always seem to run
synchronously.

I''ve boiled down the code to a simple "lab" experiment below. In this
console app you''ll see that instance one comes back after roughly 4
seconds and then instance two comes back in 8 seconds, twice the time.
This indicates that it is wait on the first thread to finish. Why
won''t they run concurrently?

I''ve tried my best to make sure that the thread types are MTAThread
before calling the COM objects. Also, in VB I made sure the project
threading model was "Apartment Threaded" and the Instancing set to
GlobalUseMulti.

Any ideas???
Thanks

******************* .NET C# CONSOLE TEST APP ********************
using System;
using System.Threading;

namespace ComThreadTest
{
class MyConsoleApp
{
[MTAThread]
static void Main(string[] args)
{
TestClass test1 = new TestClass("1");
TestClass test2 = new TestClass("2");

Thread th = new Thread(new ThreadStart(test1.Go));
th.ApartmentState = ApartmentState.MTA;
th.Start();

th = new Thread(new ThreadStart(test2.Go));
th.ApartmentState = ApartmentState.MTA;
th.Start();
}
}

public class TestClass
{
public DotNetSleeperClass dotnet;
public MyCom.SleeperClass com;
public string mName;

public TestClass(string name)
{
mName = name;
dotnet = new DotNetSleeperClass();
com = new MyCom.SleeperClass();
}

[MTAThread]
public void Go()
{
DateTime start = DateTime.Now;
Console.WriteLine(mName + " OUT at " +
start.ToString("hh:mm:ss:fff"));

//THIS WORK FINE BECAUSE IT''S SIMPLE MANAGED CODE.
//dotnet.Go();

//THIS BLOCKS OTHER THREADS WHILE IT RUNS com.Go();

DateTime finish = DateTime.Now;
TimeSpan ts = finish - start;
Console.WriteLine(mName + " IN at " +
finish.ToString("hh:mm:ss:fff") + " ELAPSED=" +
ts.TotalMilliseconds.ToString() + " milliseconds.");
Console.WriteLine("Press any key to continue...");
Console.Read();
}
}

public class DotNetSleeperClass
{
public DotNetSleeperClass() {}

public void Go()
{
Thread.Sleep(3000);
}
}

}
******************* VB6 ACTIVEX DLL ********************
Option Explicit
Public Sub Go()
''On my box this runs in about 4 seconds to run.
Dim a, b, c
For a = 1 To 1000
For b = 1 To 1000
c = a Mod b
DoEvents
Next b
Next a
End Sub



VB6 COM对象是STA对象,这意味着它们必须在STA线程上运行。

您确实从两个MTA线程创建了两个对象实例,但对象本身将运行在单个(COM(OLE)创建的)STA

线程上,来自两个MTA线程的访问将被封送和同步。

所以你应该做的是,将线程初始化为STA,以便每个对象在他自己的STA线程上运行而不进行编组,然后你就可以了。


Willy。

Mark Sisson <毫安** @ corporatedigital.com>在消息新闻中写道:88 ************************** @ posting.google.c om ...
VB6 COM objects are STA objects, that means they must run on an STA thread.
You did create two instances of the object from two MTA threads, but the object itself will run on a single (COM (OLE) created) STA
thread, and access from the two MTA threads will be marshaled and synchronized.
So what you should do is, initialize the threads as STA so that each objects runs on his own STA thread without marshaling and you
will be fine.

Willy.
"Mark Sisson" <ma**@corporatedigital.com> wrote in message news:88**************************@posting.google.c om...
嘿所有。
我有一个遗留的COM dll,我想在我的多线程C#
应用程序中使用。问题是,当我创建互操作对象的几个实例并在他们自己的线程上启动它们时,它们似乎总是同步运行。

我已经将代码归结为代码简单的实验室实验如下。在这个
控制台应用程序中,你会看到实例一在大约4
秒后返回,然后实例2在8秒内返回,两倍的时间。
这表明它正在等待在第一个线程完成。为什么
不会同时运行?

在调用COM对象之前,我已经尽力确保线程类型是MTAThread
。此外,在VB中,我确保项目的线程模型是Apartment Threaded。和Instancing设置为GlobalUseMulti。

任何想法???
谢谢

************* ****** .NET C#CONSOLE TEST APP ********************
使用System;
使用System.Threading;

命名空间ComThreadTest
{MyconsoleApp类
{MTAThread]
static void Main(string [] args)
{<测试类test1 =新的TestClass(1);
TestClass test2 = new TestClass(" 2")

线程th =新线程(新的ThreadStart(test1。) Go));
th.ApartmentState = ApartmentState.MTA;
th.Start();

th = new Thread(new ThreadStart(test2.Go));
th.ApartmentState = ApartmentState.MTA;
th.Start();
}

公共类TestClass
{
public DotNetSleeperClass dotnet;
public MyCom.SleeperClass com;
public string mName;

public TestClass(s​​tring name)
{
mName = name;
dotnet = new DotNetSleeperClass();
com = new MyCom.SleeperClass();
}

[MTAThread]
public void Go()
{DateTime start = DateTime.Now;
Console.WriteLine(mName +" OUT在 +
start.ToString(" hh:mm:ss:fff"));

//这项工作很精细,因为它是简单的管理代码。
// dotnet.Go();

//当它运行时阻止其他线程com.Go();

DateTime finish = DateTime.Now;
TimeSpan ts =完成 - 开始;
Console.WriteLine(mName +" IN at" +
finish.ToString(" hh:mm:ss:fff")+" ELAPSED =" +
ts.TotalMilliseconds.ToString()+毫秒。;
Console.WriteLine(按任意键继续......);
Console.Read() ;
}

公共类DotNetSleeperClass
公共DotNetSleeperClass(){}

public void Go()
{
Thread.Sleep(3000);
}
}

}

******* ************ VB6 ACTIVEX DLL ********************
选项明确
Public Sub Go()
''在我的盒子上运行大约4秒钟。
昏暗a,b,c
对于a = 1到1000
对于b = 1到1000
c = a Mod b
DoEvents
下一步b
下一页
End Sub
Hey all.
I''ve got a legacy COM dll that I''d like to use in my multithreaded C#
app. Problem though is when I create several instances of the interop
object and start them on their own threads they always seem to run
synchronously.

I''ve boiled down the code to a simple "lab" experiment below. In this
console app you''ll see that instance one comes back after roughly 4
seconds and then instance two comes back in 8 seconds, twice the time.
This indicates that it is wait on the first thread to finish. Why
won''t they run concurrently?

I''ve tried my best to make sure that the thread types are MTAThread
before calling the COM objects. Also, in VB I made sure the project
threading model was "Apartment Threaded" and the Instancing set to
GlobalUseMulti.

Any ideas???
Thanks

******************* .NET C# CONSOLE TEST APP ********************
using System;
using System.Threading;

namespace ComThreadTest
{
class MyConsoleApp
{
[MTAThread]
static void Main(string[] args)
{
TestClass test1 = new TestClass("1");
TestClass test2 = new TestClass("2");

Thread th = new Thread(new ThreadStart(test1.Go));
th.ApartmentState = ApartmentState.MTA;
th.Start();

th = new Thread(new ThreadStart(test2.Go));
th.ApartmentState = ApartmentState.MTA;
th.Start();
}
}

public class TestClass
{
public DotNetSleeperClass dotnet;
public MyCom.SleeperClass com;
public string mName;

public TestClass(string name)
{
mName = name;
dotnet = new DotNetSleeperClass();
com = new MyCom.SleeperClass();
}

[MTAThread]
public void Go()
{
DateTime start = DateTime.Now;
Console.WriteLine(mName + " OUT at " +
start.ToString("hh:mm:ss:fff"));

//THIS WORK FINE BECAUSE IT''S SIMPLE MANAGED CODE.
//dotnet.Go();

//THIS BLOCKS OTHER THREADS WHILE IT RUNS com.Go();

DateTime finish = DateTime.Now;
TimeSpan ts = finish - start;
Console.WriteLine(mName + " IN at " +
finish.ToString("hh:mm:ss:fff") + " ELAPSED=" +
ts.TotalMilliseconds.ToString() + " milliseconds.");
Console.WriteLine("Press any key to continue...");
Console.Read();
}
}

public class DotNetSleeperClass
{
public DotNetSleeperClass() {}

public void Go()
{
Thread.Sleep(3000);
}
}

}
******************* VB6 ACTIVEX DLL ********************
Option Explicit
Public Sub Go()
''On my box this runs in about 4 seconds to run.
Dim a, b, c
For a = 1 To 1000
For b = 1 To 1000
c = a Mod b
DoEvents
Next b
Next a
End Sub



感谢Willy和Justin。你的评论都很有帮助,但我仍然没有接近解决方案。我发现了更多关于

上下文切换的帖子我开始觉得当你在一个处理器系统上运行时你可以运行
任何上下文切换都不能保证

。最新的COM代码和时序结果为
以下。请注意,我强迫上下文切换的唯一弱尝试是带睡眠的
。有没有更强大的WinAPI,我可以参与

强制上下文线程?


现在让我们走出实验室一秒钟在现实世界中,我的
生产COM组件并没有坐在循环中做数学计算。相反,它执行HTTP POST并将结果存储到SQL中。由于POST将占用95%的处理时间

,CPU-time-slice-manager会将此视为上下文切换

机会(我希望)?或者我注定要认为我将永远能够让我的多线程COM对象同时发送4个并发的

HTTP POST?这似乎很荒谬,虽然我的CPU只是在等待HTTP结果(需要在5

和25秒之间)之外什么都不做,所有其他线程都无法做到至少在此期间发送他们的

HTTP POST。这就是我的架构的重点

是多线程的。


再次感谢。

mark


=============== COM CODE,从不切换上下文===============

选项明确

私有声明子睡眠库kernel32 (ByVal dwMilliseconds As

Long)


Public Function Go()As String

Dim rslt As String

Dim a As Double

Dim b As Double

Dim c As Double

Dim CR As String


CR = Chr(13)+ Chr(10)

rslt = CR +" 00%=" + FormatDateTime(现在,vbLongTime)+ CR

对于a = 1到1000

如果一个Mod 100 = 0那么

rslt = rslt + " " + CStr(a * 100/2000)+%= +

FormatDateTime(现在,vbLongTime)+ CR

睡眠(100)

结束如果

对于b = 1到1000

DoEvents

下一个b

下一个

Go = rslt

结束功能


====================结果发现.NET CALL APP ===============

#1的统计数据

00%= 7:07:39 AM

10%= 7:07:40 AM

20%= 7:07:41 AM

30%= 7:07:41 AM

40%= 7:07:42 AM

50%= 7:07:43 AM

60%= 7:07:43 AM

70%= 7:07:44 AM

80%= 7:07:45 AM

90%= 7:07:45 AM

100%= 7:07:46 AM

#2的统计数据

00%= 7:07:39 AM

10%= 7:07:47 AM

20%= 7:07:48 AM

30%= 7:07: 49 AM

40%= 7:07:49 AM

50%= 7:07:50 AM

60%= 7:07 :51 AM

70%= 7:07:52 AM

80%= 7:07:53 AM

90%= 7: 07:53

100%= 7:07:54 AM
Thank Willy and Justin. You comments are both helpful but I''m still
not much closer to a solution. I found a few more posts on
context-switching I''m starting to get the feeling that when you''re
running on a single processor system that you can''t be guaranteed of
any context switching. The latest COM code and timing results are
below. Note that my only weak attempt at forcing a context-switch is
with Sleep. Are there any more potent WinAPI''s that I could enlist to
force the context-thread?

Now let''s step out of the lab for a second. In the real world my
production COM component doesn''t sit in a loop doing math
calculations. Instead it executes an HTTP POST and stores the results
into SQL. Since the POST is what will take 95% of processing time
will the CPU-time-slice-manager see this as a context-switching
opportunity (I hope)? Or am I doomed to think that I will ever be
able to get my multi-threaded COM objects to be sending 4 concurrent
HTTP POSTs simultaneously? It''s seems ludicrous that while my CPU is
doing nothing but waiting for the HTTP results (which take between 5
and 25 seconds) that all other threads could not at least send their
HTTP POSTs in the meantime. That''s the whole point of my architecture
being multi-threaded.

Thanks again.
mark

=============== COM CODE THAT NEVER SWITCHES CONTEXT ===============
Option Explicit
Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As
Long)

Public Function Go() As String
Dim rslt As String
Dim a As Double
Dim b As Double
Dim c As Double
Dim CR As String

CR = Chr(13) + Chr(10)
rslt = CR + " 00%=" + FormatDateTime(Now, vbLongTime) + CR
For a = 1 To 1000
If a Mod 100 = 0 Then
rslt = rslt + " " + CStr(a * 100 / 2000) + "%=" +
FormatDateTime(Now, vbLongTime) + CR
Sleep (100)
End If
For b = 1 To 1000
c = a Mod b
DoEvents
Next b
Next a
Go = rslt
End Function

==================== RESULTS SEEN IN .NET CALL APP ===============
Stats for #1
00%=7:07:39 AM
10%=7:07:40 AM
20%=7:07:41 AM
30%=7:07:41 AM
40%=7:07:42 AM
50%=7:07:43 AM
60%=7:07:43 AM
70%=7:07:44 AM
80%=7:07:45 AM
90%=7:07:45 AM
100%=7:07:46 AM

Stats for #2
00%=7:07:39 AM
10%=7:07:47 AM
20%=7:07:48 AM
30%=7:07:49 AM
40%=7:07:49 AM
50%=7:07:50 AM
60%=7:07:51 AM
70%=7:07:52 AM
80%=7:07:53 AM
90%=7:07:53 AM
100%=7:07:54 AM


这篇关于Interop的多线程并发的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆