473,408 Members | 2,030 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,408 software developers and data experts.

multiple threads writing to WebBrowser, getting deadlocked

I have multiple threads writing to WebBrowser (using a function that
checks InvokedRequired, and if so, invokes itself on the WebBrowser
thread) and they are getting deadlocked.

They only deadlock when I use lock { } around the call to
WebBrowser.Write to ensure thread safety!

Does any one have experience with such a thing?

Zytan

Apr 2 '07 #1
18 6811
Zytan <zy**********@gmail.comwrote:
I have multiple threads writing to WebBrowser (using a function that
checks InvokedRequired, and if so, invokes itself on the WebBrowser
thread) and they are getting deadlocked.

They only deadlock when I use lock { } around the call to
WebBrowser.Write to ensure thread safety!

Does any one have experience with such a thing?
Hang on - do you mean you've already got a lock when you call Invoke?

Could you post a short but complete program which demonstrates the
problem?

See http://www.pobox.com/~skeet/csharp/complete.html for details of
what I mean by that.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too
Apr 2 '07 #2
Zytan wrote:
I have multiple threads writing to WebBrowser (using a function that
checks InvokedRequired, and if so, invokes itself on the WebBrowser
thread) and they are getting deadlocked.

They only deadlock when I use lock { } around the call to
WebBrowser.Write to ensure thread safety!
Using 'lock' doesn't make sense.

WebBrowser is a WinForms control, and should only be accessed from its
UI thread. So, if you use Control.InvokeRequired, and properly use
Control.Invoke or Control.BeginInvoke to marshal your call over to the
UI control, you don't need to use 'lock', because all code that touches
the WebBrowser control is serialized on its UI thread.

Access to Control.InvokeRequired is not required to be synchronized - in
fact, it would be easy to deadlock if it and its ilk did require
synchronization. Similarly, Control.Invoke, Control.BeginInvoke etc.
don't require synchronization - check docs for Control.InvokeRequired.

-- Barry

--
http://barrkel.blogspot.com/
Apr 2 '07 #3
Zytan wrote:
I have multiple threads writing to WebBrowser (using a function that
checks InvokedRequired, and if so, invokes itself on the WebBrowser
thread) and they are getting deadlocked.

They only deadlock when I use lock { } around the call to
WebBrowser.Write to ensure thread safety!

Does any one have experience with such a thing?
Well if you do:

class Foo
{
//Some stuff to setup a WebBrowser control called WebBrowser

public void SomeMethod()
{
lock(WebBrowser)
{
if(InvokeRequired)
{
Invoke(new SomeDelegate(SomeMethod));
} else {
//Do something
}
}
}
}

This will result in a deadlock when called from a thread other than the
UI thread. Instead, you should do:

class Foo
{
//Some stuff to setup a WebBrowser control called WebBrowser

public void SomeMethod()
{
if(InvokeRequired)
{
Invoke(new SomeDelegate(SomeMethod));
} else {
lock(WebBrowser)
{
//Do something
}
}
}
}
}

If you want more than that, post some code :-)

Alun Harford
Apr 2 '07 #4
Hang on - do you mean you've already got a lock when you call Invoke?

Yes.
Could you post a short but complete program which demonstrates the
problem?
Ok, I made a small program that does nothing but start a timer that
ticks every second. It calls MyWriteLine. This calls (using
InvokeRequired + Invoke, if needed) WebBrowser.Document.Write. (Well,
it makes sure the WebBrowser has a Document to write to, and if not,
navgiates to "about:blank" first).

Then, I made a thread that I can start/stop with two buttons, this
thread does the same thing as the timer. The stop button calls
myThread.Join(); to wait for the thread to complete.

Starting the thread is fine, they both update te WebBrowser. Stopping
the thread hangs on myThread.Join();

I thought this is a problem with synchronization, so I made a wrapper
to MyWriteLine, and placed a critical section lock into. Thus,
MyWriteLine is only called within a critical section. Now, the
program hangs at the lock statement when I stop the thread.

I'd post the code, but I don't have it with me at the moment. I'll
code it again, and do some more testing. I have a feeling that
replacing WebBrowser with another control solves the problem.

Zytan

Apr 3 '07 #5
WebBrowser is a WinForms control, and should only be accessed from its
UI thread. So, if you use Control.InvokeRequired, and properly use
Control.Invoke or Control.BeginInvoke to marshal your call over to the
UI control, you don't need to use 'lock', because all code that touches
the WebBrowser control is serialized on its UI thread.
Ok, I knew that Control.Invoke made the call on the same thread as
Control, but, I am unaware of what it's doing internally. I don't
know what 'marshal' actually means. So, it basically means it is
serialized on the Control's thread, meaning that all calls to
Control.Invoke are called in order, one after the other, and thus
multiple threads all calling Control.Invoke to update a single control
will be safe.
Access to Control.InvokeRequired is not required to be synchronized - in
fact, it would be easy to deadlock if it and its ilk did require
synchronization. Similarly, Control.Invoke, Control.BeginInvoke etc.
don't require synchronization - check docs for Control.InvokeRequired.
Ok, thanks, Barry

Zytan

Apr 3 '07 #6
Well if you do:
>
class Foo
{
//Some stuff to setup a WebBrowser control called WebBrowser

public void SomeMethod()
{
lock(WebBrowser)
{
if(InvokeRequired)
{
Invoke(new SomeDelegate(SomeMethod));
} else {
//Do something
}
}
}
}
Ha ha, yes, I wasn't stupid enough to recusively attempt to enter the
same lock. The lock I have is in a wrapper around SomeMethod().
If you want more than that, post some code :-)
I will once I make my small source example again.

Zytan

Apr 3 '07 #7
Code example: Make two Buttons (btnStart, btnStop), and one
WebBroswer (webLog), and paste this into the main Form:

Thread myThread;
private volatile bool m_ThreadProcessing = false;
private int m_count = 0;

private void ThreadFunc()
{
while (m_ThreadProcessing)
{
Thread.Sleep(400);
m_count++;
MyWrite(webLog, m_count + "<br>" +
Environment.NewLine);
}
}

private void btnStart_Click(object sender, EventArgs e)
{
if (myThread == null)
{
myThread = new Thread(ThreadFunc);
m_ThreadProcessing = true;
myThread.Start();
}
}

private void btnStop_Click(object sender, EventArgs e)
{
if (myThread != null)
{
m_ThreadProcessing = false;
myThread.Join(); // <------------- HANGS HERE!
myThread = null;
}
}

delegate void MyWrite_Delegate(WebBrowser web, string str);
public static void MyWrite(WebBrowser web, string str)
{
if (web.InvokeRequired)
{
MyWrite_Delegate funcptr = MyWrite;
object[] args = { web, str };
web.Invoke(funcptr, args);
}
else
{
if (web.Document == null) web.Navigate("about:blank");
web.Document.Write(str);
web.Document.Window.ScrollTo(0, int.MaxValue); //
scroll to bottom
}
}

Note that this hangs only with this single thread accessing the
WebBrowser. Not even the main thread accesses it! (I'm preparing for
you guys to show me the obvious error I've been missing all day.)

Zytan

Apr 3 '07 #8
On Apr 3, 4:49 pm, "Zytan" <zytanlith...@gmail.comwrote:
Code example: Make two Buttons (btnStart, btnStop), and one
WebBroswer (webLog), and paste this into the main Form:
<snip>

Yes, that would hang. You're using "Invoke" from myThread - that will
block until the delegate you've passed it has been executed on the UI
thread.

Now, from the UI thread, you're calling myThread.Join - that will
block until myThread has completed.

So, how can either of them get anywhere?

Jon

Apr 3 '07 #9
Yes, that would hang. You're using "Invoke" from myThread - that will
block until the delegate you've passed it has been executed on the UI
thread.

Now, from the UI thread, you're calling myThread.Join - that will
block until myThread has completed.
Ok, it's a deadlock.

I was uncertain as what happened as a result of Invoke. Thanks to
your reply, I have a better idea. The message queue in the main
thread is processing the 'stop button clicked' message, which is
running Thread.Join, which is waiting for myThread to terminate. The
message queue is stalled (never a good idea).

myThread is upset that it doesn't own the control (as it shouldn't,
since it doesn't have a message queue to maintain it), so it tells the
GUI thread to deal with it, via Invoke. Now, my understanding is that
Invoke is *not a function pointer call* (perhaps this is why they call
them delegates, instead of function pointers?), it is a message placed
in the GUI thread. (This is why an earlier post mentioned that
Control.Invoke is serialized, meaning they are handled one at a time,
because the message queue processes one message at a time. So, if
multiple threads posted multiple messages into the queue, it still
does one at a time, and my WebBrowser doesn't need a critical
section.) But, the GUI thread has its message queue stalled.

Solution #1: Use BeginInvoke, which is a 'non blocking' call (it must
call Win32's PostMessage instead of SendMessage).

Solution #2: Don't use Thread.Join(). The examples show it, so I
used it. Often, it is unneeded.

Solution #3: Don't make the worker threads access the GUI.

Solution #4: Use BackgroundWorker, which I presume doesn't have this
issue (I think it calls a function of yours when it is done, so you
never have to call something like BackgroundWorker.Join, which likely
doesn't exist).

Does that all make sense?

Zytan

Apr 3 '07 #10
private void ThreadFunc()
{
while (m_ThreadProcessing)
{
Thread.Sleep(400);
m_count++;
MyWrite(webLog, m_count + "<br>" +
Environment.NewLine);
}
}
For the curious:

Move the Thread.Sleep(400) to AFTER the MyWrite call, and it works,
always. Thanks to Jon's great reply, I now know why. This single
difference was the difference between two identical apps I made, and I
was dumbfounded as to why one worked and the other didn't.
Thread.Sleep() at the end doesn't give the deadlock of Control.Invoke
and Thread.Join to occur.

Thanks, Jon.

Zytan

Apr 3 '07 #11
Zytan <zy**********@gmail.comwrote:

<snip>
For the curious:

Move the Thread.Sleep(400) to AFTER the MyWrite call, and it works,
always. Thanks to Jon's great reply, I now know why. This single
difference was the difference between two identical apps I made, and I
was dumbfounded as to why one worked and the other didn't.
Thread.Sleep() at the end doesn't give the deadlock of Control.Invoke
and Thread.Join to occur.
Hmm. You've still got a potential deadlock, unfortunately.

If you click the stop button at just the wrong time, it will still
break. You can end up with btnStop_Click running, waiting for myThread
to finish - but with myThread waiting for a call to web.Invoke to
finish.

Using BeginInvoke is certainly a reasonable way of avoiding this,
although I'd avoid calling Thread.Join in the UI thread too.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too
Apr 3 '07 #12
Hmm. You've still got a potential deadlock, unfortunately.

Yes, I knew that... I should have been accurate and said that if you
click it just at the right time, you have a chance to create the
deadlock, since the same conditions still exist. But, the likelihood
is 1 in a billion.

I realy didn't mean this was a solution. I meant to show how code
that you would think is broken appears to run fine. It's still
broken. And this really threw me off.
Using BeginInvoke is certainly a reasonable way of avoiding this,
although I'd avoid calling Thread.Join in the UI thread too.
Yes, I choose both (call Control.BeginInvoke, and to not call
Thread.Join)

Zytan

Apr 3 '07 #13
On Apr 3, 12:32 am, Alun Harford <devn...@alunharford.co.ukwrote:
Zytan wrote:
I have multiple threads writing to WebBrowser (using a function that
checks InvokedRequired, and if so, invokes itself on the WebBrowser
thread) and they are getting deadlocked.
They only deadlock when I use lock { } around the call to
WebBrowser.Write to ensure thread safety!
Does any one have experience with such a thing?

Well if you do:

class Foo
{
//Some stuff to setup a WebBrowser control called WebBrowser

public void SomeMethod()
{
lock(WebBrowser)
{
if(InvokeRequired)
{
Invoke(new SomeDelegate(SomeMethod));
} else {
//Do something
}
}
}

}

This will result in a deadlock when called from a thread other than the
UI thread. Instead, you should do:

class Foo
{
//Some stuff to setup a WebBrowser control called WebBrowser

public void SomeMethod()
{
if(InvokeRequired)
{
Invoke(new SomeDelegate(SomeMethod));
} else {
lock(WebBrowser)
{
//Do something
}
}
}
}

}

If you want more than that, post some code :-)

Alun Harford
I you don't need returnvalues or out-parameters, it is better to use
BeginInvoke() instead of Invoke().

See here: http://kristofverbiest.blogspot.com/...gininvoke.html

Kristof

Apr 4 '07 #14
When you have the primary thread, owning the window, sleeping it usually
blocks the messages for the time that you put it to sleep. This is
because Windows identifies threads in two ways: as a UI thread or a
worker thread and the UI thread is meant to handle all GUI operations.
Obviously, if the UI thread (and if it is a primary thread as well) is
put to sleep, it will seem to simulate a deadlock whereas, it may just
be a matter of blocking messages.

Please refer to the following blog for details on sleeping on a UI
thread:

http://blogs.msdn.com/oldnewthing/ar...10/529525.aspx

Another can be found in the below link to msdn:

http://msdn.microsoft.com/msdnmag/is...asicInstincts/

and on:

http://www.yoda.arachsys.com/csharp/...winforms.shtml
with regards,
J.V.Ravichandran
- http://www.geocities.com/
jvravichandran
- Or, just search on "J.V.Ravichandran"
at http://www.Google.com

*** Sent via Developersdex http://www.developersdex.com ***
Apr 4 '07 #15
On Apr 4, 8:11 am, Ravichandran J.V. <jvravichand...@yahoo.comwrote:
When you have the primary thread, owning the window, sleeping it usually
blocks the messages for the time that you put it to sleep. This is
because Windows identifies threads in two ways: as a UI thread or a
worker thread and the UI thread is meant to handle all GUI operations.
Obviously, if the UI thread (and if it is a primary thread as well) is
put to sleep, it will seem to simulate a deadlock whereas, it may just
be a matter of blocking messages.
It was the worker thread which had the call to Sleep in it. The UI
thread had the call to Join in it, and that *was* deadlocking (rather
than just waiting for messages which would get processed eventually)
because the thread it was trying to join was also waiting for a
message to be completed in the UI thread.

Jon

Apr 4 '07 #16
<snip>
Code example: Make two Buttons (btnStart, btnStop), and one
WebBroswer (webLog), and paste this into the main Form:
</snip>

Does this not mean that the main form would contain the main method and
if I remember the signature well, it would be a STA thread and hence,
would be the main thread as well. Would this not make the thread the UI
thread or am I missing something?

with regards,
J.V.Ravichandran
- http://www.geocities.com/
jvravichandran
- Or, just search on "J.V.Ravichandran"
at http://www.Google.com

*** Sent via Developersdex http://www.developersdex.com ***
Apr 4 '07 #17
On Apr 4, 1:32 pm, Ravichandran J.V. <jvravichand...@yahoo.comwrote:
<snip>
Code example: Make two Buttons (btnStart, btnStop), and one
WebBroswer (webLog), and paste this into the main Form:
</snip>

Does this not mean that the main form would contain the main method and
if I remember the signature well, it would be a STA thread and hence,
would be the main thread as well. Would this not make the thread the UI
thread or am I missing something?
Yes, that would be the UI thread. But the only method calling Sleep is
ThreadFunc, which executes in the worker thread creates by btnStart.

Jon

Apr 4 '07 #18
I you don't need returnvalues or out-parameters, it is better to use
BeginInvoke() instead of Invoke().

See here:http://kristofverbiest.blogspot.com/...e-prefer-begin...
Kristof, this is precisely what I needed to know. Jon told me what
the problem I was having was, and I already knew that BeginInvoke was
the answer, once the problem was clear.

Thanks for the link,

Zytan

Apr 4 '07 #19

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

2
by: Lad | last post by:
I would like to use httplib/urllib to download webpages from 3 different websites.From my script I want to open 3 webbrowser windows( 3 threads) and open in each thread( window) pages from a...
7
by: Guyon Morée | last post by:
If I have multiple threads reading from the same file, would that be a problem? if yes, how would I solve it? Let's say I want to take it a step further and start writing to 1 file form...
4
by: Tony Liu | last post by:
Hi, how can I create multiple new file handles of a file without having to share to file to the other processes? I have a file that will be accessed by multiple threads in my application, each...
32
by: tshad | last post by:
Can you do a search for more that one string in another string? Something like: someString.IndexOf("something1","something2","something3",0) or would you have to do something like: if...
6
by: RahimAsif | last post by:
Hi guys, I would like some advice on thread programming using C#. I am writing an application that communicates with a panel over ethernet, collects data and writes it to a file. The way the...
6
by: cj | last post by:
As many of you know I'm writing a TCP/IP server with multiple threads handling multiple short conversations (submit a short string, send back a sort string). Threads are created as needed to...
11
by: Olie | last post by:
This post is realy to get some opinions on the best way of getting fast comunication between multiple applications. I have scowered the web for imformation on this subject and have just found...
2
by: PAzevedo | last post by:
I have this Hashtable of Hashtables, and I'm accessing this object from multiple threads, now the Hashtable object is thread safe for reading, but not for writing, so I lock the object every time I...
2
by: scriptlearner | last post by:
OS: Solaris 9 Python Version: 2.4.4 I need to log certain data in a worker thread; however, I am getting an error now when I use two worker threads. I think the problem comes from the line...
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new...
0
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.