469,917 Members | 1,578 Online
Bytes | Developer Community
New Post

Home Posts Topics Members FAQ

Post your question to a community of 469,917 developers. It's quick & easy.

Problems with Threading and CDO in C# Winforms app

I have written a winforms application that launches approximately 150
threads with
Thread.ThreadStart()

Each thread uses CDO 1.21 to logon to a different Exchange mailbox and
send/receive a number of mail messages, reporting back to the UI thread
through the use of a Queue object. When all messages that are expected have
been received, each thread sends a final update to the UI and the method
should exit, which should terminate the thread.

Everything works well for the most part, although I am doing battle with the
Outlook Security dialog on some mailboxes.

When all threads have completed their work, the Exit button on the UI is
enabled. When I click it, the Application.Exit() function is called, and the
UI disappears, but the application continues to run. In the debug
environment eventually I get a thread deadlock message. At this point, there
should only be one thread running.

I have read numerous articles on threading and examined many samples and
cannot see anything wrong with the way I have coded this application.

If anyone has experienced this type of problem, or has a suggestion on how I
could try to nail this down, I would appreciate it. Is it possible the CDO
object is part of the problem?

Thanks in advance

Steve


Mar 20 '06 #1
11 1958
Please see my previous post. Do you get anything out of my post?

Regards,
Lars-Inge Tønnessen
Mar 20 '06 #2

Are you sure all of your threads have entered the STA? This is required by
CDO.
Note that I see no reason at all to have 150 threads, and all reporting back
to the UI thread, is this part of a contest or what? You are just wasting
150MB of memory for the thread stacks and you waste a lot of CPU resources
just to switch the threads which will just slow down the whole application.
Willy.

"Steve Smith" <st***********@shaw.ca> wrote in message
news:uI**************@TK2MSFTNGP09.phx.gbl...
|I have written a winforms application that launches approximately 150
| threads with
| Thread.ThreadStart()
|
| Each thread uses CDO 1.21 to logon to a different Exchange mailbox and
| send/receive a number of mail messages, reporting back to the UI thread
| through the use of a Queue object. When all messages that are expected
have
| been received, each thread sends a final update to the UI and the method
| should exit, which should terminate the thread.
|
| Everything works well for the most part, although I am doing battle with
the
| Outlook Security dialog on some mailboxes.
|
| When all threads have completed their work, the Exit button on the UI is
| enabled. When I click it, the Application.Exit() function is called, and
the
| UI disappears, but the application continues to run. In the debug
| environment eventually I get a thread deadlock message. At this point,
there
| should only be one thread running.
|
| I have read numerous articles on threading and examined many samples and
| cannot see anything wrong with the way I have coded this application.
|
| If anyone has experienced this type of problem, or has a suggestion on how
I
| could try to nail this down, I would appreciate it. Is it possible the CDO
| object is part of the problem?
|
| Thanks in advance
|
| Steve
|
|
|
|
Mar 21 '06 #3
Have you set the threads as Background threads? By setting them to
Background CLR ends the process of the background threads when
foreground threads are terminated.

Mar 21 '06 #4
I did include the following code when launching the threads at one time, but
have since commented it out to see if it was part of the problem.

y.theThread.SetApartmentState(ApartmentState.STA);

There is no contest here, just trying to get the job done in the most
efficient manner. The appilcation seems to work quite well. What use to take
45 minutes is now complete in less than 10 minutes, the only remaining
problem is the Application.Exit() issue I have described.

The old single-threaded VB6 application takes close to 45 minutes to
complete. Some of the CDO calls are very expensive, particularly the mailbox
Logon, so I expected that executing those calls once instead of 2 or more
times would be an improvement.

This application is run on a dedicated, well-equipped workstation, after
system changes have been made to a large Exchange environment. It's purpose
is to confirm that each mailbox store on each server has mail flowing
between each store, as well as to and from external mail systems. It also
confirms access to Public Folders, and verifies that the virus detection
and notification systems are working.

Thanks for the feedback.

Steve
"Willy Denoyette [MVP]" <wi*************@telenet.be> wrote in message
news:un**************@TK2MSFTNGP14.phx.gbl...

Are you sure all of your threads have entered the STA? This is required by
CDO.
Note that I see no reason at all to have 150 threads, and all reporting
back
to the UI thread, is this part of a contest or what? You are just wasting
150MB of memory for the thread stacks and you waste a lot of CPU resources
just to switch the threads which will just slow down the whole
application.
Willy.

"Steve Smith" <st***********@shaw.ca> wrote in message
news:uI**************@TK2MSFTNGP09.phx.gbl...
|I have written a winforms application that launches approximately 150
| threads with
| Thread.ThreadStart()
|
| Each thread uses CDO 1.21 to logon to a different Exchange mailbox and
| send/receive a number of mail messages, reporting back to the UI thread
| through the use of a Queue object. When all messages that are expected
have
| been received, each thread sends a final update to the UI and the method
| should exit, which should terminate the thread.
|
| Everything works well for the most part, although I am doing battle with
the
| Outlook Security dialog on some mailboxes.
|
| When all threads have completed their work, the Exit button on the UI is
| enabled. When I click it, the Application.Exit() function is called, and
the
| UI disappears, but the application continues to run. In the debug
| environment eventually I get a thread deadlock message. At this point,
there
| should only be one thread running.
|
| I have read numerous articles on threading and examined many samples and
| cannot see anything wrong with the way I have coded this application.
|
| If anyone has experienced this type of problem, or has a suggestion on
how
I
| could try to nail this down, I would appreciate it. Is it possible the
CDO
| object is part of the problem?
|
| Thanks in advance
|
| Steve
|
|
|
|

Mar 21 '06 #5
Yes, I have "y.theThread.IsBackground = true;" in my code.

Thanks for the feedback.

Steve

"Naveen" <na*********************@gmail.com> wrote in message
news:11**********************@t31g2000cwb.googlegr oups.com...
Have you set the threads as Background threads? By setting them to
Background CLR ends the process of the background threads when
foreground threads are terminated.

Mar 21 '06 #6
Well, the CDO library (CDO 1.2.1) is a client side COM automation library,
that means it is designed to be used from a Windows client style
application, not from a multi-threaded server style application. The CDO
library uses 'apartment' threaded objects, that means their instances must
and will run in an STA thread. The only STA thread in a windows application
(by default) is the UI thread, so, if you create CDO object instances from
auxiliary threads in your application, and you don't initialize these
threads to enter a STA, your COM objects will run in the UI thread and your
call will have to be marshaled.
That means that in your case you have 150 threads that do nothing else than
waiting for their calls to be serialized to the one and only STA (UI)
thread, I would not call this very inefficient. But there is more, you have
to make sure that the UI thread survives the other threads and that it
survives the finalizer thread. This is needed because the finalizer thread
will have to 'finalize' the RCW's whenever you are releasing the COM object
references. Now the question is, how do you release the object references?
Is this done before the thread procedure returns, or are you simply relying
on the finalizer to clean-up? If it's the latter, you are in trouble, the
finalizer thread will most certainly be unable to release all the RCW's
because the STA will be torn down before or while your finalizers run. The
only option you have to solve this is:
- restrict the number of threads (say 2 or 3, more makes no sense, really),
- initialize them as STA threads,
- make sure you release the COM objects and pump the message queue (by
calling WaitForPendingFinalizers) before returning from your thread
procedures, and
- make sure no exceptions in your thread procedures can go unhandled.

Willy.

"Steve Smith" <st***********@shaw.ca> wrote in message
news:eP**************@tk2msftngp13.phx.gbl...
|I did include the following code when launching the threads at one time,
but
| have since commented it out to see if it was part of the problem.
|
| y.theThread.SetApartmentState(ApartmentState.STA);
|
| There is no contest here, just trying to get the job done in the most
| efficient manner. The appilcation seems to work quite well. What use to
take
| 45 minutes is now complete in less than 10 minutes, the only remaining
| problem is the Application.Exit() issue I have described.
|
| The old single-threaded VB6 application takes close to 45 minutes to
| complete. Some of the CDO calls are very expensive, particularly the
mailbox
| Logon, so I expected that executing those calls once instead of 2 or more
| times would be an improvement.
|
| This application is run on a dedicated, well-equipped workstation, after
| system changes have been made to a large Exchange environment. It's
purpose
| is to confirm that each mailbox store on each server has mail flowing
| between each store, as well as to and from external mail systems. It also
| confirms access to Public Folders, and verifies that the virus detection
| and notification systems are working.
|
| Thanks for the feedback.
|
| Steve
|
|
| "Willy Denoyette [MVP]" <wi*************@telenet.be> wrote in message
| news:un**************@TK2MSFTNGP14.phx.gbl...
| >
| > Are you sure all of your threads have entered the STA? This is required
by
| > CDO.
| > Note that I see no reason at all to have 150 threads, and all reporting
| > back
| > to the UI thread, is this part of a contest or what? You are just
wasting
| > 150MB of memory for the thread stacks and you waste a lot of CPU
resources
| > just to switch the threads which will just slow down the whole
| > application.
| >
| >
| > Willy.
| >
| > "Steve Smith" <st***********@shaw.ca> wrote in message
| > news:uI**************@TK2MSFTNGP09.phx.gbl...
| > |I have written a winforms application that launches approximately 150
| > | threads with
| > | Thread.ThreadStart()
| > |
| > | Each thread uses CDO 1.21 to logon to a different Exchange mailbox and
| > | send/receive a number of mail messages, reporting back to the UI
thread
| > | through the use of a Queue object. When all messages that are expected
| > have
| > | been received, each thread sends a final update to the UI and the
method
| > | should exit, which should terminate the thread.
| > |
| > | Everything works well for the most part, although I am doing battle
with
| > the
| > | Outlook Security dialog on some mailboxes.
| > |
| > | When all threads have completed their work, the Exit button on the UI
is
| > | enabled. When I click it, the Application.Exit() function is called,
and
| > the
| > | UI disappears, but the application continues to run. In the debug
| > | environment eventually I get a thread deadlock message. At this point,
| > there
| > | should only be one thread running.
| > |
| > | I have read numerous articles on threading and examined many samples
and
| > | cannot see anything wrong with the way I have coded this application.
| > |
| > | If anyone has experienced this type of problem, or has a suggestion on
| > how
| > I
| > | could try to nail this down, I would appreciate it. Is it possible the
| > CDO
| > | object is part of the problem?
| > |
| > | Thanks in advance
| > |
| > | Steve
| > |
| > |
| > |
| > |
| >
| >
|
|
Mar 21 '06 #7
I am definitely starting the threads as STA

I have gone through the method launched in a thread, and the functions that
it calls and have verified that I am cleaning up the COM objects that I
instantiate, either explicitly, or by the variables going out of scope.

I have added a call to WaitForPendingFinalizers at the end of my thread
method, and have retested, however it seems to make no difference.

I tried adding a call to WaitForPendingFinalizers in my btnExit function and
when execution reaches this call, my app stops here and never goes beyond
this call. TaskManager shows the app taking some small slices of CPU now and
again, usuually within a couple of minutes I get a COM Exception for a
thread deadlock.

I'm intrigued by your suggestion that 3 threads should be able to handle
this, and would like to know more about what you had in mind.

If I divide the work (150 mailboxes) by 3 threads, each thread would have to
process 50 mailboxes. If this is done in a serial manner, I expect the
elapsed runtime would be at least 20 minutes. Is there another way to have
50 MAPI sessions going in a single thread, so I can complete the work with
an elapsed time of 5 minutes or less that the app enjoys now with 150
threads?

Thanks in advance for any suggestions you might have.

Steve


"Willy Denoyette [MVP]" <wi*************@telenet.be> wrote in message
news:ea**************@TK2MSFTNGP09.phx.gbl...
Well, the CDO library (CDO 1.2.1) is a client side COM automation library,
that means it is designed to be used from a Windows client style
application, not from a multi-threaded server style application. The CDO
library uses 'apartment' threaded objects, that means their instances must
and will run in an STA thread. The only STA thread in a windows
application
(by default) is the UI thread, so, if you create CDO object instances from
auxiliary threads in your application, and you don't initialize these
threads to enter a STA, your COM objects will run in the UI thread and
your
call will have to be marshaled.
That means that in your case you have 150 threads that do nothing else
than
waiting for their calls to be serialized to the one and only STA (UI)
thread, I would not call this very inefficient. But there is more, you
have
to make sure that the UI thread survives the other threads and that it
survives the finalizer thread. This is needed because the finalizer thread
will have to 'finalize' the RCW's whenever you are releasing the COM
object
references. Now the question is, how do you release the object references?
Is this done before the thread procedure returns, or are you simply
relying
on the finalizer to clean-up? If it's the latter, you are in trouble, the
finalizer thread will most certainly be unable to release all the RCW's
because the STA will be torn down before or while your finalizers run. The
only option you have to solve this is:
- restrict the number of threads (say 2 or 3, more makes no sense,
really),
- initialize them as STA threads,
- make sure you release the COM objects and pump the message queue (by
calling WaitForPendingFinalizers) before returning from your thread
procedures, and
- make sure no exceptions in your thread procedures can go unhandled.

Willy.

"Steve Smith" <st***********@shaw.ca> wrote in message
news:eP**************@tk2msftngp13.phx.gbl...
|I did include the following code when launching the threads at one time,
but
| have since commented it out to see if it was part of the problem.
|
| y.theThread.SetApartmentState(ApartmentState.STA);
|
| There is no contest here, just trying to get the job done in the most
| efficient manner. The appilcation seems to work quite well. What use to
take
| 45 minutes is now complete in less than 10 minutes, the only remaining
| problem is the Application.Exit() issue I have described.
|
| The old single-threaded VB6 application takes close to 45 minutes to
| complete. Some of the CDO calls are very expensive, particularly the
mailbox
| Logon, so I expected that executing those calls once instead of 2 or
more
| times would be an improvement.
|
| This application is run on a dedicated, well-equipped workstation, after
| system changes have been made to a large Exchange environment. It's
purpose
| is to confirm that each mailbox store on each server has mail flowing
| between each store, as well as to and from external mail systems. It
also
| confirms access to Public Folders, and verifies that the virus
detection
| and notification systems are working.
|
| Thanks for the feedback.
|
| Steve
|
|
| "Willy Denoyette [MVP]" <wi*************@telenet.be> wrote in message
| news:un**************@TK2MSFTNGP14.phx.gbl...
| >
| > Are you sure all of your threads have entered the STA? This is
required
by
| > CDO.
| > Note that I see no reason at all to have 150 threads, and all
reporting
| > back
| > to the UI thread, is this part of a contest or what? You are just
wasting
| > 150MB of memory for the thread stacks and you waste a lot of CPU
resources
| > just to switch the threads which will just slow down the whole
| > application.
| >
| >
| > Willy.
| >
| > "Steve Smith" <st***********@shaw.ca> wrote in message
| > news:uI**************@TK2MSFTNGP09.phx.gbl...
| > |I have written a winforms application that launches approximately 150
| > | threads with
| > | Thread.ThreadStart()
| > |
| > | Each thread uses CDO 1.21 to logon to a different Exchange mailbox
and
| > | send/receive a number of mail messages, reporting back to the UI
thread
| > | through the use of a Queue object. When all messages that are
expected
| > have
| > | been received, each thread sends a final update to the UI and the
method
| > | should exit, which should terminate the thread.
| > |
| > | Everything works well for the most part, although I am doing battle
with
| > the
| > | Outlook Security dialog on some mailboxes.
| > |
| > | When all threads have completed their work, the Exit button on the
UI
is
| > | enabled. When I click it, the Application.Exit() function is called,
and
| > the
| > | UI disappears, but the application continues to run. In the debug
| > | environment eventually I get a thread deadlock message. At this
point,
| > there
| > | should only be one thread running.
| > |
| > | I have read numerous articles on threading and examined many samples
and
| > | cannot see anything wrong with the way I have coded this
application.
| > |
| > | If anyone has experienced this type of problem, or has a suggestion
on
| > how
| > I
| > | could try to nail this down, I would appreciate it. Is it possible
the
| > CDO
| > | object is part of the problem?
| > |
| > | Thanks in advance
| > |
| > | Steve
| > |
| > |
| > |
| > |
| >
| >
|
|

Mar 22 '06 #8

"Steve Smith" <st***********@shaw.ca> wrote in message
news:uW*************@TK2MSFTNGP09.phx.gbl...
|I am definitely starting the threads as STA
|
| I have gone through the method launched in a thread, and the functions
that
| it calls and have verified that I am cleaning up the COM objects that I
| instantiate, either explicitly, or by the variables going out of scope.
|

Try to release them explicitely, when you let the references go out of
scope, you rely on the finalizer to clean them up, but if you return from
the thread before the GC has done two sweeps, the thread (and the message
queue) will be gone and with him the STA before the finalizer has run. If
you don't want or can't release them explicitely, you have to do the
following before returning from your thread procedure:

...
CdoObj = null; // optional in release builds
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
GC.WaitForPendingFinalizers();
return;
}

It should be clear by now that this has to be done because you run apartment
threaded COM code on a non UI thread (as it was designed for).
When running your (apt.)COM objects on the (single) UI thread, this one
keeps pumping the message queue (that's it's job) and the framework calls
GC.Collect as part of it's form close application exit procedure, so you
won't have (well, exceptionally you do) this kind of issues.
| I have added a call to WaitForPendingFinalizers at the end of my thread
| method, and have retested, however it seems to make no difference.
|

See above...

| I tried adding a call to WaitForPendingFinalizers in my btnExit function
and
| when execution reaches this call, my app stops here and never goes beyond
| this call.

That means that the finalizer thread is blocked. Calling
WaitForPendingFinalizers makes no sense either, there are no COM objects to
be released here.
TaskManager shows the app taking some small slices of CPU now and
| again, usuually within a couple of minutes I get a COM Exception for a
| thread deadlock.
|
| I'm intrigued by your suggestion that 3 threads should be able to handle
| this, and would like to know more about what you had in mind.
|

Try first to solve above issue, and I show you later how you can handle
this.

| If I divide the work (150 mailboxes) by 3 threads, each thread would have
to
| process 50 mailboxes. If this is done in a serial manner, I expect the
| elapsed runtime would be at least 20 minutes. Is there another way to have
| 50 MAPI sessions going in a single thread, so I can complete the work with
| an elapsed time of 5 minutes or less that the app enjoys now with 150
| threads?
|
| Thanks in advance for any suggestions you might have.
|
| Steve
|
Willy.
Mar 22 '06 #9
Willy,
| Well, the CDO library (CDO 1.2.1) is a client side COM automation library,
| that means it is designed to be used from a Windows client style
| application, not from a multi-threaded server style application.
Actually CDO 1.2.1 is also a server side COM automation library that is
installed as part of Exchange Server! The client (Outlook) version causes
the afore mentioned security prompt, while the server (Exchange Server)
version does not. The client version is STA & really doesn't like being
started in an MTA (it appears to be a bug in the client version), while the
server version can run both MTA or STA (based on the apartment you start it
in)!

In both cases CDO 1.2.1 is explicitly not supported under .NET, however COM
interop is. I have used CDO 1.2.1 via COM interop with great success under
..NET 1.x, I have not converted the application to .NET 2.0 yet. I use the
server version of CDO 1.2.1 in a mutlithreaded .NET Window Service app.
Sean,
Rather then start 150 threads, I normally use the thread pool, which
implicitly limits me to about 20 connections. The rational is that with 150
threads you have 150 open connections on the client & on the server, which
is consuming & competing for both client & server resources, probably
hurting performance, rather then helping. I suspect there is a "sweet"
number between 20 & 150 that provides optimal performance. This "sweet"
number would be based on size & shape of the server and size & shape of the
client, as well as possibly network size and other network/server concurrent
usage... Network should not affect my app as my app runs as a service on the
Exchange Server box, which in itself is another resource being competed
for...

| - make sure you release the COM objects and pump the message queue (by
| calling WaitForPendingFinalizers) before returning from your thread
| procedures, and
In this instance I would recommend Marshal.ReleaseComObject in a loop to
ensure that the COM objects are released (for .NET 2.0 I would recommend
Marshal.FinalReleaseComObject).

Taking into account all the potential problems that ReleaseComObject
introduces...

http://blogs.msdn.com/yvesdolc/archi...17/115379.aspx
http://blogs.msdn.com/cbrumme/archiv.../16/51355.aspx
http://samgentile.com/blog/archive/2003/04/17/5797.aspx
http://msdn2.microsoft.com/en-us/lib...ct(VS.80).aspx

http://msdn2.microsoft.com/en-us/lib...ct(VS.80).aspx

--
Hope this helps
Jay [MVP - Outlook]
..NET Application Architect, Enthusiast, & Evangelist
T.S. Bradley - http://www.tsbradley.net
"Willy Denoyette [MVP]" <wi*************@telenet.be> wrote in message
news:ea**************@TK2MSFTNGP09.phx.gbl...
| Well, the CDO library (CDO 1.2.1) is a client side COM automation library,
| that means it is designed to be used from a Windows client style
| application, not from a multi-threaded server style application. The CDO
| library uses 'apartment' threaded objects, that means their instances must
| and will run in an STA thread. The only STA thread in a windows
application
| (by default) is the UI thread, so, if you create CDO object instances from
| auxiliary threads in your application, and you don't initialize these
| threads to enter a STA, your COM objects will run in the UI thread and
your
| call will have to be marshaled.
| That means that in your case you have 150 threads that do nothing else
than
| waiting for their calls to be serialized to the one and only STA (UI)
| thread, I would not call this very inefficient. But there is more, you
have
| to make sure that the UI thread survives the other threads and that it
| survives the finalizer thread. This is needed because the finalizer thread
| will have to 'finalize' the RCW's whenever you are releasing the COM
object
| references. Now the question is, how do you release the object references?
| Is this done before the thread procedure returns, or are you simply
relying
| on the finalizer to clean-up? If it's the latter, you are in trouble, the
| finalizer thread will most certainly be unable to release all the RCW's
| because the STA will be torn down before or while your finalizers run. The
| only option you have to solve this is:
| - restrict the number of threads (say 2 or 3, more makes no sense,
really),
| - initialize them as STA threads,
| - make sure you release the COM objects and pump the message queue (by
| calling WaitForPendingFinalizers) before returning from your thread
| procedures, and
| - make sure no exceptions in your thread procedures can go unhandled.
|
| Willy.
|
|
|
|
|
| "Steve Smith" <st***********@shaw.ca> wrote in message
| news:eP**************@tk2msftngp13.phx.gbl...
||I did include the following code when launching the threads at one time,
| but
|| have since commented it out to see if it was part of the problem.
||
|| y.theThread.SetApartmentState(ApartmentState.STA);
||
|| There is no contest here, just trying to get the job done in the most
|| efficient manner. The appilcation seems to work quite well. What use to
| take
|| 45 minutes is now complete in less than 10 minutes, the only remaining
|| problem is the Application.Exit() issue I have described.
||
|| The old single-threaded VB6 application takes close to 45 minutes to
|| complete. Some of the CDO calls are very expensive, particularly the
| mailbox
|| Logon, so I expected that executing those calls once instead of 2 or more
|| times would be an improvement.
||
|| This application is run on a dedicated, well-equipped workstation, after
|| system changes have been made to a large Exchange environment. It's
| purpose
|| is to confirm that each mailbox store on each server has mail flowing
|| between each store, as well as to and from external mail systems. It also
|| confirms access to Public Folders, and verifies that the virus detection
|| and notification systems are working.
||
|| Thanks for the feedback.
||
|| Steve
||
||
|| "Willy Denoyette [MVP]" <wi*************@telenet.be> wrote in message
|| news:un**************@TK2MSFTNGP14.phx.gbl...
|| >
|| > Are you sure all of your threads have entered the STA? This is required
| by
|| > CDO.
|| > Note that I see no reason at all to have 150 threads, and all reporting
|| > back
|| > to the UI thread, is this part of a contest or what? You are just
| wasting
|| > 150MB of memory for the thread stacks and you waste a lot of CPU
| resources
|| > just to switch the threads which will just slow down the whole
|| > application.
|| >
|| >
|| > Willy.
|| >
|| > "Steve Smith" <st***********@shaw.ca> wrote in message
|| > news:uI**************@TK2MSFTNGP09.phx.gbl...
|| > |I have written a winforms application that launches approximately 150
|| > | threads with
|| > | Thread.ThreadStart()
|| > |
|| > | Each thread uses CDO 1.21 to logon to a different Exchange mailbox
and
|| > | send/receive a number of mail messages, reporting back to the UI
| thread
|| > | through the use of a Queue object. When all messages that are
expected
|| > have
|| > | been received, each thread sends a final update to the UI and the
| method
|| > | should exit, which should terminate the thread.
|| > |
|| > | Everything works well for the most part, although I am doing battle
| with
|| > the
|| > | Outlook Security dialog on some mailboxes.
|| > |
|| > | When all threads have completed their work, the Exit button on the UI
| is
|| > | enabled. When I click it, the Application.Exit() function is called,
| and
|| > the
|| > | UI disappears, but the application continues to run. In the debug
|| > | environment eventually I get a thread deadlock message. At this
point,
|| > there
|| > | should only be one thread running.
|| > |
|| > | I have read numerous articles on threading and examined many samples
| and
|| > | cannot see anything wrong with the way I have coded this application.
|| > |
|| > | If anyone has experienced this type of problem, or has a suggestion
on
|| > how
|| > I
|| > | could try to nail this down, I would appreciate it. Is it possible
the
|| > CDO
|| > | object is part of the problem?
|| > |
|| > | Thanks in advance
|| > |
|| > | Steve
|| > |
|| > |
|| > |
|| > |
|| >
|| >
||
||
|
|
Mar 27 '06 #10
Right, what a mess, really. CDO 1.2.1 that comes with Outlook is "client
side" technology, CDO 1.2.1 that comes with Exchange client is "server side"
technology. And we have CDO for Exchange (CDOEX) and CDO for Windows 2000
(CDOSYS) which is also Server side. And don't let us start about CDONTS and
CDO 1.1.

Anyway, the CDO version which comes with outlook is 'apartment' threaded,
so it runs in an STA (COM won't create an apartment threaded object in an
MTA ever), I remember there was a problem with cross-apartment marshaling in
1.2.1, but I supposed this is no longer an issue (could be wrong though).
The Exchange client version is marked 'Both', so it can run in both an STA's
and MTA's, but in .NET it's important to know what the object requirements
are, and as both support STA I would opt for STA threads anyway, unless you
make sure you are talking to the Exchange version, if you don't you are
looking for troubles, really.

Willy.

"Jay B. Harlow [MVP - Outlook]" <Ja************@tsbradley.net> wrote in
message news:%2****************@tk2msftngp13.phx.gbl...
| Willy,
|| Well, the CDO library (CDO 1.2.1) is a client side COM automation
library,
|| that means it is designed to be used from a Windows client style
|| application, not from a multi-threaded server style application.
| Actually CDO 1.2.1 is also a server side COM automation library that is
| installed as part of Exchange Server! The client (Outlook) version causes
| the afore mentioned security prompt, while the server (Exchange Server)
| version does not. The client version is STA & really doesn't like being
| started in an MTA (it appears to be a bug in the client version), while
the
| server version can run both MTA or STA (based on the apartment you start
it
| in)!
|
| In both cases CDO 1.2.1 is explicitly not supported under .NET, however
COM
| interop is. I have used CDO 1.2.1 via COM interop with great success under
| .NET 1.x, I have not converted the application to .NET 2.0 yet. I use the
| server version of CDO 1.2.1 in a mutlithreaded .NET Window Service app.
|
|
| Sean,
| Rather then start 150 threads, I normally use the thread pool, which
| implicitly limits me to about 20 connections. The rational is that with
150
| threads you have 150 open connections on the client & on the server, which
| is consuming & competing for both client & server resources, probably
| hurting performance, rather then helping. I suspect there is a "sweet"
| number between 20 & 150 that provides optimal performance. This "sweet"
| number would be based on size & shape of the server and size & shape of
the
| client, as well as possibly network size and other network/server
concurrent
| usage... Network should not affect my app as my app runs as a service on
the
| Exchange Server box, which in itself is another resource being competed
| for...
|
|| - make sure you release the COM objects and pump the message queue (by
|| calling WaitForPendingFinalizers) before returning from your thread
|| procedures, and
| In this instance I would recommend Marshal.ReleaseComObject in a loop to
| ensure that the COM objects are released (for .NET 2.0 I would recommend
| Marshal.FinalReleaseComObject).
|
| Taking into account all the potential problems that ReleaseComObject
| introduces...
|
| http://blogs.msdn.com/yvesdolc/archi...17/115379.aspx
| http://blogs.msdn.com/cbrumme/archiv.../16/51355.aspx
| http://samgentile.com/blog/archive/2003/04/17/5797.aspx
|
|
|
http://msdn2.microsoft.com/en-us/lib...ct(VS.80).aspx
|
|
http://msdn2.microsoft.com/en-us/lib...ct(VS.80).aspx
|
| --
| Hope this helps
| Jay [MVP - Outlook]
| .NET Application Architect, Enthusiast, & Evangelist
| T.S. Bradley - http://www.tsbradley.net
|
|
| "Willy Denoyette [MVP]" <wi*************@telenet.be> wrote in message
| news:ea**************@TK2MSFTNGP09.phx.gbl...
|| Well, the CDO library (CDO 1.2.1) is a client side COM automation
library,
|| that means it is designed to be used from a Windows client style
|| application, not from a multi-threaded server style application. The CDO
|| library uses 'apartment' threaded objects, that means their instances
must
|| and will run in an STA thread. The only STA thread in a windows
| application
|| (by default) is the UI thread, so, if you create CDO object instances
from
|| auxiliary threads in your application, and you don't initialize these
|| threads to enter a STA, your COM objects will run in the UI thread and
| your
|| call will have to be marshaled.
|| That means that in your case you have 150 threads that do nothing else
| than
|| waiting for their calls to be serialized to the one and only STA (UI)
|| thread, I would not call this very inefficient. But there is more, you
| have
|| to make sure that the UI thread survives the other threads and that it
|| survives the finalizer thread. This is needed because the finalizer
thread
|| will have to 'finalize' the RCW's whenever you are releasing the COM
| object
|| references. Now the question is, how do you release the object
references?
|| Is this done before the thread procedure returns, or are you simply
| relying
|| on the finalizer to clean-up? If it's the latter, you are in trouble, the
|| finalizer thread will most certainly be unable to release all the RCW's
|| because the STA will be torn down before or while your finalizers run.
The
|| only option you have to solve this is:
|| - restrict the number of threads (say 2 or 3, more makes no sense,
| really),
|| - initialize them as STA threads,
|| - make sure you release the COM objects and pump the message queue (by
|| calling WaitForPendingFinalizers) before returning from your thread
|| procedures, and
|| - make sure no exceptions in your thread procedures can go unhandled.
||
|| Willy.
||
||
||
||
||
|| "Steve Smith" <st***********@shaw.ca> wrote in message
|| news:eP**************@tk2msftngp13.phx.gbl...
|||I did include the following code when launching the threads at one time,
|| but
||| have since commented it out to see if it was part of the problem.
|||
||| y.theThread.SetApartmentState(ApartmentState.STA);
|||
||| There is no contest here, just trying to get the job done in the most
||| efficient manner. The appilcation seems to work quite well. What use to
|| take
||| 45 minutes is now complete in less than 10 minutes, the only remaining
||| problem is the Application.Exit() issue I have described.
|||
||| The old single-threaded VB6 application takes close to 45 minutes to
||| complete. Some of the CDO calls are very expensive, particularly the
|| mailbox
||| Logon, so I expected that executing those calls once instead of 2 or
more
||| times would be an improvement.
|||
||| This application is run on a dedicated, well-equipped workstation, after
||| system changes have been made to a large Exchange environment. It's
|| purpose
||| is to confirm that each mailbox store on each server has mail flowing
||| between each store, as well as to and from external mail systems. It
also
||| confirms access to Public Folders, and verifies that the virus
detection
||| and notification systems are working.
|||
||| Thanks for the feedback.
|||
||| Steve
|||
|||
||| "Willy Denoyette [MVP]" <wi*************@telenet.be> wrote in message
||| news:un**************@TK2MSFTNGP14.phx.gbl...
||| >
||| > Are you sure all of your threads have entered the STA? This is
required
|| by
||| > CDO.
||| > Note that I see no reason at all to have 150 threads, and all
reporting
||| > back
||| > to the UI thread, is this part of a contest or what? You are just
|| wasting
||| > 150MB of memory for the thread stacks and you waste a lot of CPU
|| resources
||| > just to switch the threads which will just slow down the whole
||| > application.
||| >
||| >
||| > Willy.
||| >
||| > "Steve Smith" <st***********@shaw.ca> wrote in message
||| > news:uI**************@TK2MSFTNGP09.phx.gbl...
||| > |I have written a winforms application that launches approximately 150
||| > | threads with
||| > | Thread.ThreadStart()
||| > |
||| > | Each thread uses CDO 1.21 to logon to a different Exchange mailbox
| and
||| > | send/receive a number of mail messages, reporting back to the UI
|| thread
||| > | through the use of a Queue object. When all messages that are
| expected
||| > have
||| > | been received, each thread sends a final update to the UI and the
|| method
||| > | should exit, which should terminate the thread.
||| > |
||| > | Everything works well for the most part, although I am doing battle
|| with
||| > the
||| > | Outlook Security dialog on some mailboxes.
||| > |
||| > | When all threads have completed their work, the Exit button on the
UI
|| is
||| > | enabled. When I click it, the Application.Exit() function is called,
|| and
||| > the
||| > | UI disappears, but the application continues to run. In the debug
||| > | environment eventually I get a thread deadlock message. At this
| point,
||| > there
||| > | should only be one thread running.
||| > |
||| > | I have read numerous articles on threading and examined many samples
|| and
||| > | cannot see anything wrong with the way I have coded this
application.
||| > |
||| > | If anyone has experienced this type of problem, or has a suggestion
| on
||| > how
||| > I
||| > | could try to nail this down, I would appreciate it. Is it possible
| the
||| > CDO
||| > | object is part of the problem?
||| > |
||| > | Thanks in advance
||| > |
||| > | Steve
||| > |
||| > |
||| > |
||| > |
||| >
||| >
|||
|||
||
||
|
|
Mar 27 '06 #11
Thanks Jay, I will try invoking the FinalReleaseComObject on the CDO session
object when the thread has completed it's work, just before it terminates.

I suppose I should look into using WebDAV instead of using CDO. The few
times I've looked at equivalent code for accessing a mailbox in WebDAV vs
CDO, I found it to be complex and non-intuitive.

I'm only using CDO for it's ability to do dynamic logons, and to easily send
and receive mail through an Exchange mailbox.

I'll try your suggestion on the threads, and will look into WebDAV in the
very near future.

Thanks
Steve
"Jay B. Harlow [MVP - Outlook]" <Ja************@tsbradley.net> wrote in
message news:%2****************@tk2msftngp13.phx.gbl...
Willy,
| Well, the CDO library (CDO 1.2.1) is a client side COM automation
library,
| that means it is designed to be used from a Windows client style
| application, not from a multi-threaded server style application.
Actually CDO 1.2.1 is also a server side COM automation library that is
installed as part of Exchange Server! The client (Outlook) version causes
the afore mentioned security prompt, while the server (Exchange Server)
version does not. The client version is STA & really doesn't like being
started in an MTA (it appears to be a bug in the client version), while
the
server version can run both MTA or STA (based on the apartment you start
it
in)!

In both cases CDO 1.2.1 is explicitly not supported under .NET, however
COM
interop is. I have used CDO 1.2.1 via COM interop with great success under
.NET 1.x, I have not converted the application to .NET 2.0 yet. I use the
server version of CDO 1.2.1 in a mutlithreaded .NET Window Service app.
Sean,
Rather then start 150 threads, I normally use the thread pool, which
implicitly limits me to about 20 connections. The rational is that with
150
threads you have 150 open connections on the client & on the server, which
is consuming & competing for both client & server resources, probably
hurting performance, rather then helping. I suspect there is a "sweet"
number between 20 & 150 that provides optimal performance. This "sweet"
number would be based on size & shape of the server and size & shape of
the
client, as well as possibly network size and other network/server
concurrent
usage... Network should not affect my app as my app runs as a service on
the
Exchange Server box, which in itself is another resource being competed
for...

| - make sure you release the COM objects and pump the message queue (by
| calling WaitForPendingFinalizers) before returning from your thread
| procedures, and
In this instance I would recommend Marshal.ReleaseComObject in a loop to
ensure that the COM objects are released (for .NET 2.0 I would recommend
Marshal.FinalReleaseComObject).

Taking into account all the potential problems that ReleaseComObject
introduces...

http://blogs.msdn.com/yvesdolc/archi...17/115379.aspx
http://blogs.msdn.com/cbrumme/archiv.../16/51355.aspx
http://samgentile.com/blog/archive/2003/04/17/5797.aspx
http://msdn2.microsoft.com/en-us/lib...ct(VS.80).aspx

http://msdn2.microsoft.com/en-us/lib...ct(VS.80).aspx

--
Hope this helps
Jay [MVP - Outlook]
.NET Application Architect, Enthusiast, & Evangelist
T.S. Bradley - http://www.tsbradley.net
"Willy Denoyette [MVP]" <wi*************@telenet.be> wrote in message
news:ea**************@TK2MSFTNGP09.phx.gbl...
| Well, the CDO library (CDO 1.2.1) is a client side COM automation
library,
| that means it is designed to be used from a Windows client style
| application, not from a multi-threaded server style application. The CDO
| library uses 'apartment' threaded objects, that means their instances
must
| and will run in an STA thread. The only STA thread in a windows
application
| (by default) is the UI thread, so, if you create CDO object instances
from
| auxiliary threads in your application, and you don't initialize these
| threads to enter a STA, your COM objects will run in the UI thread and
your
| call will have to be marshaled.
| That means that in your case you have 150 threads that do nothing else
than
| waiting for their calls to be serialized to the one and only STA (UI)
| thread, I would not call this very inefficient. But there is more, you
have
| to make sure that the UI thread survives the other threads and that it
| survives the finalizer thread. This is needed because the finalizer
thread
| will have to 'finalize' the RCW's whenever you are releasing the COM
object
| references. Now the question is, how do you release the object
references?
| Is this done before the thread procedure returns, or are you simply
relying
| on the finalizer to clean-up? If it's the latter, you are in trouble,
the
| finalizer thread will most certainly be unable to release all the RCW's
| because the STA will be torn down before or while your finalizers run.
The
| only option you have to solve this is:
| - restrict the number of threads (say 2 or 3, more makes no sense,
really),
| - initialize them as STA threads,
| - make sure you release the COM objects and pump the message queue (by
| calling WaitForPendingFinalizers) before returning from your thread
| procedures, and
| - make sure no exceptions in your thread procedures can go unhandled.
|
| Willy.
|
|
|
|
|
| "Steve Smith" <st***********@shaw.ca> wrote in message
| news:eP**************@tk2msftngp13.phx.gbl...
||I did include the following code when launching the threads at one time,
| but
|| have since commented it out to see if it was part of the problem.
||
|| y.theThread.SetApartmentState(ApartmentState.STA);
||
|| There is no contest here, just trying to get the job done in the most
|| efficient manner. The appilcation seems to work quite well. What use to
| take
|| 45 minutes is now complete in less than 10 minutes, the only remaining
|| problem is the Application.Exit() issue I have described.
||
|| The old single-threaded VB6 application takes close to 45 minutes to
|| complete. Some of the CDO calls are very expensive, particularly the
| mailbox
|| Logon, so I expected that executing those calls once instead of 2 or
more
|| times would be an improvement.
||
|| This application is run on a dedicated, well-equipped workstation,
after
|| system changes have been made to a large Exchange environment. It's
| purpose
|| is to confirm that each mailbox store on each server has mail flowing
|| between each store, as well as to and from external mail systems. It
also
|| confirms access to Public Folders, and verifies that the virus
detection
|| and notification systems are working.
||
|| Thanks for the feedback.
||
|| Steve
||
||
|| "Willy Denoyette [MVP]" <wi*************@telenet.be> wrote in message
|| news:un**************@TK2MSFTNGP14.phx.gbl...
|| >
|| > Are you sure all of your threads have entered the STA? This is
required
| by
|| > CDO.
|| > Note that I see no reason at all to have 150 threads, and all
reporting
|| > back
|| > to the UI thread, is this part of a contest or what? You are just
| wasting
|| > 150MB of memory for the thread stacks and you waste a lot of CPU
| resources
|| > just to switch the threads which will just slow down the whole
|| > application.
|| >
|| >
|| > Willy.
|| >
|| > "Steve Smith" <st***********@shaw.ca> wrote in message
|| > news:uI**************@TK2MSFTNGP09.phx.gbl...
|| > |I have written a winforms application that launches approximately
150
|| > | threads with
|| > | Thread.ThreadStart()
|| > |
|| > | Each thread uses CDO 1.21 to logon to a different Exchange mailbox
and
|| > | send/receive a number of mail messages, reporting back to the UI
| thread
|| > | through the use of a Queue object. When all messages that are
expected
|| > have
|| > | been received, each thread sends a final update to the UI and the
| method
|| > | should exit, which should terminate the thread.
|| > |
|| > | Everything works well for the most part, although I am doing battle
| with
|| > the
|| > | Outlook Security dialog on some mailboxes.
|| > |
|| > | When all threads have completed their work, the Exit button on the
UI
| is
|| > | enabled. When I click it, the Application.Exit() function is
called,
| and
|| > the
|| > | UI disappears, but the application continues to run. In the debug
|| > | environment eventually I get a thread deadlock message. At this
point,
|| > there
|| > | should only be one thread running.
|| > |
|| > | I have read numerous articles on threading and examined many
samples
| and
|| > | cannot see anything wrong with the way I have coded this
application.
|| > |
|| > | If anyone has experienced this type of problem, or has a suggestion
on
|| > how
|| > I
|| > | could try to nail this down, I would appreciate it. Is it possible
the
|| > CDO
|| > | object is part of the problem?
|| > |
|| > | Thanks in advance
|| > |
|| > | Steve
|| > |
|| > |
|| > |
|| > |
|| >
|| >
||
||
|
|

Mar 27 '06 #12

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

4 posts views Thread by Charles A. Lackman | last post: by
8 posts views Thread by Z D | last post: by
5 posts views Thread by Lucvdv | last post: by
3 posts views Thread by cnickl | last post: by
4 posts views Thread by Giovanni | last post: by
7 posts views Thread by Mike P | last post: by
1 post views Thread by Waqarahmed | last post: by
reply views Thread by Salome Sato | last post: by
By using this site, you agree to our Privacy Policy and Terms of Use.