PC Review


Reply
Thread Tools Rating: Thread Rating: 1 votes, 5.00 average.

Multithreading dilemma

 
 
dan artuso
Guest
Posts: n/a
 
      22nd Nov 2007
Hi,
I'm having a problem implementing multithreading in
an app that basically recurses through the path passed to it.

The main interface is basically an explorer knockoff and the user can
perform certain
tasks on all files and directories within their selection.

The problem is that for a little bit the main UI is responsive after spawing
the thead but continued
use of it causes both the main thread and the worker thread to freeze up. If
we don't touch the UI at all,
everything works :-)
Note that we are not trying to update any form controls from the worker
thread!

I'll post what code I think is relevant and anyone who has any ideas, please
let us know!
Thanks

Dan

here is code in the form:

Private Sub cmdStart_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles cmdStart.Click
'for this quick search, the only pattern passed willl be the PermPattern

Dim objPerms As New PermPattern

'we still need a list of patterns because the Search constructor expects
it.

Dim thisPatternList As New List(Of Pattern)

'this is for each path in the listview

Dim strPaths As New List(Of String)

Dim csitems As New List(Of CShItem)

objPerms.state = PermPattern.permissions.accessDenied +
PermPattern.permissions.noAdmins + _

PermPattern.permissions.noSystem + PermPattern.permissions.notAGroup + _

PermPattern.permissions.pathTooLong

thisPatternList.Add(objPerms)

For Each lvItem As ListViewItem In Me.lvDirs.Items

Dim csItem As New CShItem(lvItem.Text)

csitems.Add(csItem)

Next

'our search object

Dim objSearch As New Search(thisPatternList, csitems, Me)

objSearch.Start()


End Sub


Here is the code in the Search class:


'rference to calling form

Private m_clientApp As Form

'create a delegate that will call back into the main form

Private Delegate Sub ProcessResults(ByVal objSearch As Search)

'create an object for the delegate

Private m_callMainForm As ProcessResults


Constructor:


Sub New(ByVal Patterns As List(Of Pattern), ByVal cshItems As List(Of
CShItem), ByVal callingForm As Form)

m_patterns = Patterns

m_results = New List(Of Result)

m_cshItems = cshItems

m_clientApp = callingForm

'dim all possible form variables

Dim policyAudit As fPolicyAudit

Dim changeOwner As fChangeOwner

'try to cast

policyAudit = TryCast(callingForm, fPolicyAudit)

changeOwner = TryCast(callingForm, fChangeOwner)

If Not IsNothing(policyAudit) Then

m_callMainForm = AddressOf policyAudit.Processresults

End If

End Sub

Protected InnerThread As New Thread(AddressOf Me.SearchFiles)

Public Sub Start()

InnerThread.SetApartmentState(ApartmentState.STA)

InnerThread.IsBackground = True

InnerThread.Priority = ThreadPriority.BelowNormal

InnerThread.Start()

End Sub

'here is the routine that starts on a seperate thread. Basically, for each
path passed in, it calls WorkWithItems which recurses through files and
folders

Public Sub SearchFiles()

Debug.Print("SearchFiles: " &
System.Threading.Thread.CurrentThread.ManagedThreadId.ToString)

m_results.Clear()

For Each csItem As CShItem In m_cshItems

WorkWithItems(csItem)

Next



Debug.Print("about to callback")

'call back to calling form passing the Search object so results can be
processed

m_clientApp.Invoke(m_callMainForm, Me)

End Sub









 
Reply With Quote
 
 
 
 
AMercer
Guest
Posts: n/a
 
      22nd Nov 2007
You should be able to start a compute bound thread (eg For loops that churn
for about 10 seconds) and still have a responsive gui while the thread is
running. When I do this, I don't call SetApartmentState, I do set
IsBackground true as you do, and I leave Priority unchanged (BelowNormal
should be unnecessary). My first suggestion is to verify that you can do
this simple threading exercise. I have no experience with setting the
apartment state, ergo I am suspicious of it.

Second, your description makes it plausible that a resource is being
consumed. Run your program and watch your process's task manager line. Make
sure everything that can be viewed is visible. Watch for a steadily rising
number like the handle count. Alternatively, use a perf tool that you are
comfortable with.

Third, as a stab in the dark and a curiosity, I would insert a Sleep(50
milliseconds) for each file you process. Is the gui more responsive with the
sleeps? Does the freeze up still happen? IMO this is unlikely to help, but
it is easy to try.

 
Reply With Quote
 
 
 
 
Michael D. Ober
Guest
Posts: n/a
 
      22nd Nov 2007
Dan,

Don't use SetApartmentState unless you are using COM Interop. Apartments
are part of the COM multithreading interface. I suspect removing this one
line will fix your performance problems.

Mike Ober.


"dan artuso" <(E-Mail Removed)> wrote in message
news:(E-Mail Removed)...
> Hi,
> I'm having a problem implementing multithreading in
> an app that basically recurses through the path passed to it.
>
> The main interface is basically an explorer knockoff and the user can
> perform certain
> tasks on all files and directories within their selection.
>
> The problem is that for a little bit the main UI is responsive after
> spawing the thead but continued
> use of it causes both the main thread and the worker thread to freeze up.
> If we don't touch the UI at all,
> everything works :-)
> Note that we are not trying to update any form controls from the worker
> thread!
>
> I'll post what code I think is relevant and anyone who has any ideas,
> please let us know!
> Thanks
>
> Dan
>
> here is code in the form:
>
> Private Sub cmdStart_Click(ByVal sender As System.Object, ByVal e As
> System.EventArgs) Handles cmdStart.Click
> 'for this quick search, the only pattern passed willl be the
> PermPattern
>
> Dim objPerms As New PermPattern
> 'we still need a list of patterns because the Search constructor
> expects it.
> Dim thisPatternList As New List(Of Pattern)
> 'this is for each path in the listview
> Dim strPaths As New List(Of String)
> Dim csitems As New List(Of CShItem)
> objPerms.state = PermPattern.permissions.accessDenied +
> PermPattern.permissions.noAdmins + _
> PermPattern.permissions.noSystem + PermPattern.permissions.notAGroup +
> _
> PermPattern.permissions.pathTooLong
> thisPatternList.Add(objPerms)
>
> For Each lvItem As ListViewItem In Me.lvDirs.Items
> Dim csItem As New CShItem(lvItem.Text)
> csitems.Add(csItem)
> Next
>
> 'our search object
>
> Dim objSearch As New Search(thisPatternList, csitems, Me)
> objSearch.Start()
> End Sub
>
>
> Here is the code in the Search class:
>
>
> 'rference to calling form
>
> Private m_clientApp As Form
> 'create a delegate that will call back into the main form
> Private Delegate Sub ProcessResults(ByVal objSearch As Search)
> 'create an object for the delegate
> Private m_callMainForm As ProcessResults
>
> Constructor:
> Sub New(ByVal Patterns As List(Of Pattern), ByVal cshItems As List(Of
> CShItem), ByVal callingForm As Form)
>
> m_patterns = Patterns
> m_results = New List(Of Result)
> m_cshItems = cshItems
> m_clientApp = callingForm
> 'dim all possible form variables
>
> Dim policyAudit As fPolicyAudit
> Dim changeOwner As fChangeOwner
> 'try to cast
> policyAudit = TryCast(callingForm, fPolicyAudit)
> changeOwner = TryCast(callingForm, fChangeOwner)
>
> If Not IsNothing(policyAudit) Then
> m_callMainForm = AddressOf policyAudit.Processresults
> End If
> End Sub
>
> Protected InnerThread As New Thread(AddressOf Me.SearchFiles)
>
> Public Sub Start()
> InnerThread.SetApartmentState(ApartmentState.STA)
> InnerThread.IsBackground = True
> InnerThread.Priority = ThreadPriority.BelowNormal
> InnerThread.Start()
> End Sub
>
> 'here is the routine that starts on a seperate thread. Basically, for each
> path passed in, it calls WorkWithItems which recurses through files and
> folders
>
> Public Sub SearchFiles()
>
> Debug.Print("SearchFiles: " &
> System.Threading.Thread.CurrentThread.ManagedThreadId.ToString)
> m_results.Clear()
> For Each csItem As CShItem In m_cshItems
> WorkWithItems(csItem)
> Next
>
> Debug.Print("about to callback")
>
> 'call back to calling form passing the Search object so results can be
> processed
> m_clientApp.Invoke(m_callMainForm, Me)
> End Sub
>



 
Reply With Quote
 
Dan
Guest
Posts: n/a
 
      22nd Nov 2007
Hi
Thanks for the replies.
This is a difficult thing to troubleshoot I know.

I tried putting the Sleep(50) in and no difference.

COM is involved in the Search routine.
WorkWithItems(ByVal csItem As CShItem)



CShItem is a class we use in the project that uses COM.

We didn't write this and there is tons of code in it.

I have a feeling this may be our problem. The array of CShItems gets passed
into the Search object before the new thread is started.

Altough I don't know why everything would freeze up simply by using the
MainForm which is executing on a different thread.

I also kept an eye on the resources in Task Manager and nothing was out of
the ordinary.

I appreciate the effort but I suspect we'll have to fix this thing on our
own!

Thanks again!

Dan


"AMercer" <(E-Mail Removed)> wrote in message
news:97085625-AA09-4F46-8B19-(E-Mail Removed)...
> You should be able to start a compute bound thread (eg For loops that
> churn
> for about 10 seconds) and still have a responsive gui while the thread is
> running. When I do this, I don't call SetApartmentState, I do set
> IsBackground true as you do, and I leave Priority unchanged (BelowNormal
> should be unnecessary). My first suggestion is to verify that you can do
> this simple threading exercise. I have no experience with setting the
> apartment state, ergo I am suspicious of it.
>
> Second, your description makes it plausible that a resource is being
> consumed. Run your program and watch your process's task manager line.
> Make
> sure everything that can be viewed is visible. Watch for a steadily
> rising
> number like the handle count. Alternatively, use a perf tool that you are
> comfortable with.
>
> Third, as a stab in the dark and a curiosity, I would insert a Sleep(50
> milliseconds) for each file you process. Is the gui more responsive with
> the
> sleeps? Does the freeze up still happen? IMO this is unlikely to help,
> but
> it is easy to try.
>



 
Reply With Quote
 
AMercer
Guest
Posts: n/a
 
      23rd Nov 2007
From your info below, I suggest you split your single process solution into
two processes. Have your gui process launch a new process to do the work
that is apparently causing the problem and that contains the software that is
difficult or impossible to fix. When it has done its work, the process
terminates, and its ill effects will be isolated in a process that is
terminating. Starting the process should be easy enough - all you need to
give the new process is a path. If there are any results that it produces,
you will need to come up with a way to get the data back into the gui process.


"Dan" wrote:

> Hi
> Thanks for the replies.
> This is a difficult thing to troubleshoot I know.
>
> I tried putting the Sleep(50) in and no difference.
>
> COM is involved in the Search routine.
> WorkWithItems(ByVal csItem As CShItem)
>
>
>
> CShItem is a class we use in the project that uses COM.
>
> We didn't write this and there is tons of code in it.
>
> I have a feeling this may be our problem. The array of CShItems gets passed
> into the Search object before the new thread is started.
>
> Altough I don't know why everything would freeze up simply by using the
> MainForm which is executing on a different thread.
>
> I also kept an eye on the resources in Task Manager and nothing was out of
> the ordinary.
>
> I appreciate the effort but I suspect we'll have to fix this thing on our
> own!
>
> Thanks again!
>
> Dan
>
>
> "AMercer" <(E-Mail Removed)> wrote in message
> news:97085625-AA09-4F46-8B19-(E-Mail Removed)...
> > You should be able to start a compute bound thread (eg For loops that
> > churn
> > for about 10 seconds) and still have a responsive gui while the thread is
> > running. When I do this, I don't call SetApartmentState, I do set
> > IsBackground true as you do, and I leave Priority unchanged (BelowNormal
> > should be unnecessary). My first suggestion is to verify that you can do
> > this simple threading exercise. I have no experience with setting the
> > apartment state, ergo I am suspicious of it.
> >
> > Second, your description makes it plausible that a resource is being
> > consumed. Run your program and watch your process's task manager line.
> > Make
> > sure everything that can be viewed is visible. Watch for a steadily
> > rising
> > number like the handle count. Alternatively, use a perf tool that you are
> > comfortable with.
> >
> > Third, as a stab in the dark and a curiosity, I would insert a Sleep(50
> > milliseconds) for each file you process. Is the gui more responsive with
> > the
> > sleeps? Does the freeze up still happen? IMO this is unlikely to help,
> > but
> > it is easy to try.
> >

>
>
>

 
Reply With Quote
 
dan artuso
Guest
Posts: n/a
 
      23rd Nov 2007
You know, I was just thinking about the 'good old days' in VB6 where I would
simulate a thread with an ActiveX exe, spawning another process. Always
worked like a charm!

Thanks for your suggestions.

Dan


"AMercer" <(E-Mail Removed)> wrote in message
news:0CF42B28-E88D-4851-87B1-(E-Mail Removed)...
> From your info below, I suggest you split your single process solution
> into
> two processes. Have your gui process launch a new process to do the work
> that is apparently causing the problem and that contains the software that
> is
> difficult or impossible to fix. When it has done its work, the process
> terminates, and its ill effects will be isolated in a process that is
> terminating. Starting the process should be easy enough - all you need to
> give the new process is a path. If there are any results that it
> produces,
> you will need to come up with a way to get the data back into the gui
> process.
>
>
> "Dan" wrote:
>
>> Hi
>> Thanks for the replies.
>> This is a difficult thing to troubleshoot I know.
>>
>> I tried putting the Sleep(50) in and no difference.
>>
>> COM is involved in the Search routine.
>> WorkWithItems(ByVal csItem As CShItem)
>>
>>
>>
>> CShItem is a class we use in the project that uses COM.
>>
>> We didn't write this and there is tons of code in it.
>>
>> I have a feeling this may be our problem. The array of CShItems gets
>> passed
>> into the Search object before the new thread is started.
>>
>> Altough I don't know why everything would freeze up simply by using the
>> MainForm which is executing on a different thread.
>>
>> I also kept an eye on the resources in Task Manager and nothing was out
>> of
>> the ordinary.
>>
>> I appreciate the effort but I suspect we'll have to fix this thing on our
>> own!
>>
>> Thanks again!
>>
>> Dan
>>
>>
>> "AMercer" <(E-Mail Removed)> wrote in message
>> news:97085625-AA09-4F46-8B19-(E-Mail Removed)...
>> > You should be able to start a compute bound thread (eg For loops that
>> > churn
>> > for about 10 seconds) and still have a responsive gui while the thread
>> > is
>> > running. When I do this, I don't call SetApartmentState, I do set
>> > IsBackground true as you do, and I leave Priority unchanged
>> > (BelowNormal
>> > should be unnecessary). My first suggestion is to verify that you can
>> > do
>> > this simple threading exercise. I have no experience with setting the
>> > apartment state, ergo I am suspicious of it.
>> >
>> > Second, your description makes it plausible that a resource is being
>> > consumed. Run your program and watch your process's task manager line.
>> > Make
>> > sure everything that can be viewed is visible. Watch for a steadily
>> > rising
>> > number like the handle count. Alternatively, use a perf tool that you
>> > are
>> > comfortable with.
>> >
>> > Third, as a stab in the dark and a curiosity, I would insert a Sleep(50
>> > milliseconds) for each file you process. Is the gui more responsive
>> > with
>> > the
>> > sleeps? Does the freeze up still happen? IMO this is unlikely to
>> > help,
>> > but
>> > it is easy to try.
>> >

>>
>>
>>



 
Reply With Quote
 
Cor Ligthert[MVP]
Guest
Posts: n/a
 
      23rd Nov 2007
Dan,

What is your goal, using multithreading or making a good solution.

In my idea we see often here people who only want multithreading because it
sounds so interesting.

Mutlithreading is only in few circumstances (and they are there for sure)
giving benefits.

As soon as your processor or a port is fulltime busy, you have no benefits,
only longer processing time and difficulties not to restart a thread because
the user just pushes a button.

Cor

 
Reply With Quote
 
Michael D. Ober
Guest
Posts: n/a
 
      24th Nov 2007
"Dan" <nothing> wrote in message
news:(E-Mail Removed)...
> Hi
> Thanks for the replies.
> This is a difficult thing to troubleshoot I know.
>
> I tried putting the Sleep(50) in and no difference.
>
> COM is involved in the Search routine.
> WorkWithItems(ByVal csItem As CShItem)
>


Dan,

Given that COM is indeed involved, you're best bet will be to split the
application into two apps. COM objects aren't Win32 (or .NET) thread aware
and really need to be in seperate processes. This is even true with the
Apartment model. All the Apartment model does is prevents the COM object
from sharing it's internal data structures across multiple processes.
Instead the Apartment model COM objects will request the calling process
allocate memory - once.

Mike.


 
Reply With Quote
 
dan artuso
Guest
Posts: n/a
 
      30th Nov 2007
Well, it seems COM was the problem.

At least it started working okay when I got rid of this code in one of our
classes:

Private Function AccountType(ByVal strSid As String) As String 'As
SID_NAME_USE

'this function returns the type of account:

'Computer, User, Group, Domain, Alias, well known

Dim ret As Boolean

Dim ptrSid As IntPtr

Dim cbSid As Integer

Dim refDomainName As New System.Text.StringBuilder

Dim rDomainName As String

Dim cbRefDomainName As Integer

Dim peUse As SID_NAME_USE

'First get the buffer sizes

ret = Win32.LookupAccountName(Nothing, strSid, Nothing, cbSid,
Nothing, cbRefDomainName, peUse)

'Adjust the buffers to the needed size

ptrSid = Marshal.AllocHGlobal(cbSid)

rDomainName = refDomainName.EnsureCapacity(cbRefDomainName)

'Get the data again, now with the changed buffers

ret = Win32.LookupAccountName(Nothing, strSid, ptrSid, cbSid,
rDomainName, cbRefDomainName, peUse)

If ret Then

'If return doesn't fail return the type)

Return peUse

End If

Marshal.FreeHGlobal(ptrSid)

End Function


Dan

"Michael D. Ober" <obermd.@.alum.mit.edu.nospam> wrote in message
news:(E-Mail Removed)...
> Dan,
>
> Don't use SetApartmentState unless you are using COM Interop. Apartments
> are part of the COM multithreading interface. I suspect removing this one
> line will fix your performance problems.
>
> Mike Ober.
>
>
> "dan artuso" <(E-Mail Removed)> wrote in message
> news:(E-Mail Removed)...
>> Hi,
>> I'm having a problem implementing multithreading in
>> an app that basically recurses through the path passed to it.
>>
>> The main interface is basically an explorer knockoff and the user can
>> perform certain
>> tasks on all files and directories within their selection.
>>
>> The problem is that for a little bit the main UI is responsive after
>> spawing the thead but continued
>> use of it causes both the main thread and the worker thread to freeze up.
>> If we don't touch the UI at all,
>> everything works :-)
>> Note that we are not trying to update any form controls from the worker
>> thread!
>>
>> I'll post what code I think is relevant and anyone who has any ideas,
>> please let us know!
>> Thanks
>>
>> Dan
>>
>> here is code in the form:
>>
>> Private Sub cmdStart_Click(ByVal sender As System.Object, ByVal e As
>> System.EventArgs) Handles cmdStart.Click
>> 'for this quick search, the only pattern passed willl be the
>> PermPattern
>>
>> Dim objPerms As New PermPattern
>> 'we still need a list of patterns because the Search constructor
>> expects it.
>> Dim thisPatternList As New List(Of Pattern)
>> 'this is for each path in the listview
>> Dim strPaths As New List(Of String)
>> Dim csitems As New List(Of CShItem)
>> objPerms.state = PermPattern.permissions.accessDenied +
>> PermPattern.permissions.noAdmins + _
>> PermPattern.permissions.noSystem + PermPattern.permissions.notAGroup +
>> _
>> PermPattern.permissions.pathTooLong
>> thisPatternList.Add(objPerms)
>>
>> For Each lvItem As ListViewItem In Me.lvDirs.Items
>> Dim csItem As New CShItem(lvItem.Text)
>> csitems.Add(csItem)
>> Next
>>
>> 'our search object
>>
>> Dim objSearch As New Search(thisPatternList, csitems, Me)
>> objSearch.Start()
>> End Sub
>>
>>
>> Here is the code in the Search class:
>>
>>
>> 'rference to calling form
>>
>> Private m_clientApp As Form
>> 'create a delegate that will call back into the main form
>> Private Delegate Sub ProcessResults(ByVal objSearch As Search)
>> 'create an object for the delegate
>> Private m_callMainForm As ProcessResults
>>
>> Constructor:
>> Sub New(ByVal Patterns As List(Of Pattern), ByVal cshItems As List(Of
>> CShItem), ByVal callingForm As Form)
>>
>> m_patterns = Patterns
>> m_results = New List(Of Result)
>> m_cshItems = cshItems
>> m_clientApp = callingForm
>> 'dim all possible form variables
>>
>> Dim policyAudit As fPolicyAudit
>> Dim changeOwner As fChangeOwner
>> 'try to cast
>> policyAudit = TryCast(callingForm, fPolicyAudit)
>> changeOwner = TryCast(callingForm, fChangeOwner)
>>
>> If Not IsNothing(policyAudit) Then
>> m_callMainForm = AddressOf policyAudit.Processresults
>> End If
>> End Sub
>>
>> Protected InnerThread As New Thread(AddressOf Me.SearchFiles)
>>
>> Public Sub Start()
>> InnerThread.SetApartmentState(ApartmentState.STA)
>> InnerThread.IsBackground = True
>> InnerThread.Priority = ThreadPriority.BelowNormal
>> InnerThread.Start()
>> End Sub
>>
>> 'here is the routine that starts on a seperate thread. Basically, for
>> each path passed in, it calls WorkWithItems which recurses through files
>> and folders
>>
>> Public Sub SearchFiles()
>>
>> Debug.Print("SearchFiles: " &
>> System.Threading.Thread.CurrentThread.ManagedThreadId.ToString)
>> m_results.Clear()
>> For Each csItem As CShItem In m_cshItems
>> WorkWithItems(csItem)
>> Next
>>
>> Debug.Print("about to callback")
>>
>> 'call back to calling form passing the Search object so results can be
>> processed
>> m_clientApp.Invoke(m_callMainForm, Me)
>> End Sub
>>

>
>



 
Reply With Quote
 
Brian Gideon
Guest
Posts: n/a
 
      30th Nov 2007
On Nov 30, 12:24 pm, "dan artuso" <dart...@NOSPAMpagepearls.com>
wrote:
> Well, it seems COM was the problem.
>
> At least it started working okay when I got rid of this code in one of our
> classes:
>
> Private Function AccountType(ByVal strSid As String) As String 'As
> SID_NAME_USE
>
> 'this function returns the type of account:
>
> 'Computer, User, Group, Domain, Alias, well known
>
> Dim ret As Boolean
>
> Dim ptrSid As IntPtr
>
> Dim cbSid As Integer
>
> Dim refDomainName As New System.Text.StringBuilder
>
> Dim rDomainName As String
>
> Dim cbRefDomainName As Integer
>
> Dim peUse As SID_NAME_USE
>
> 'First get the buffer sizes
>
> ret = Win32.LookupAccountName(Nothing, strSid, Nothing, cbSid,
> Nothing, cbRefDomainName, peUse)
>
> 'Adjust the buffers to the needed size
>
> ptrSid = Marshal.AllocHGlobal(cbSid)
>
> rDomainName = refDomainName.EnsureCapacity(cbRefDomainName)
>
> 'Get the data again, now with the changed buffers
>
> ret = Win32.LookupAccountName(Nothing, strSid, ptrSid, cbSid,
> rDomainName, cbRefDomainName, peUse)
>
> If ret Then
>
> 'If return doesn't fail return the type)
>
> Return peUse
>
> End If
>
> Marshal.FreeHGlobal(ptrSid)
>
> End Function
>
> Dan
>


I see the LookupAccountName Win32 API, but I'm not seeing any COM
objects.

You shouldn't need to allocate memory from the unmanaged heap to use
that API. Let the interop marshaller do it for you. Check out
http://www.pinvoke.net for an alternate method of declaring and using
LookupAccountName.

Also, you have a *major* memory leak here. It looks like FreeHGlobal
is only called when the function fails. You should use a Try-Finally
block to work around that issue. I'm wondering if this is part of
your problem.
 
Reply With Quote
 
 
 
Reply

Thread Tools
Rate This Thread
Rate This Thread:

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
WindowsXP and IE Dilemma Dilemma Dilemma, Please Help!! =?Utf-8?B?Qk9CMjI3?= Windows XP Configuration 0 4th Apr 2006 05:52 PM
Bug in Excel? Excel Multithreading ERROR JCChin Microsoft Excel Programming 1 1st Mar 2005 05:45 PM
Multithreading question VIhsuna Microsoft Dot NET Framework 2 2nd Sep 2003 05:56 PM
Multithreading & Controls help - 2 part question Shmulik Microsoft Dot NET Framework 0 21st Jul 2003 09:25 PM
Re: ado.net and multithreading Kathleen Dollard Microsoft ADO .NET 0 18th Jul 2003 02:23 PM


Features
 

Advertising
 

Newsgroups
 


All times are GMT +1. The time now is 01:56 PM.