From: tb2000 on
pls disregard the 6:20AM message - I hit some key which in turn fired the
posting too early. @!"ยง$%&/()=?@
sorry
tb

From: Peter Duniho on
On 2007-11-06 06:37:03 -0800, tb2000 <tb2000(a)discussions.microsoft.com> said:

> [...]
> Anyways, hopefully this is a more precise description so that the issue can
> be explained?

Well, it wasn't quite a "concise-but-complete" sample of code (it was
incomplete). However, it was enough to at least indicate one potential
problem: I had missed that you were using a semaphore in one of your
tests (you did mention that in your first post, but your later post
only discussed a mutex).

You wrote that the same thing happens when using a mutex, however the
two are not the same. A semaphore is the exception to the general rule
that a thread can't block itself, because the semaphore's behavior is
specifically to restrict acquisition to a particular number of times.

However, if you change the code you posted to use a mutex instead,
there should be no such problem. A single thread can acquire and
release a mutex arbitrarily many times (for all practical purposes
anyway).

So if the problem still happens when you use a mutex, then there's
something else going on. And if that's the case, then the code you
posted isn't going to be sufficient for solving the problem.

Pete

From: tb2000 on
Pete,

thanks again, I had hoped my code snip was sufficient - if you could let me
know what concisely ;-) you're looking for I'll be glad to post it.

The semaphore is doing exactly what I expected it to do: it prevents entry
into the code while I was hoping I could release it when done in my main
thread. Purpose was to synchronize two distinctly separate code blocks (so
that only one can be in execution at the same time). I don't really care if I
am in the same thread context or in different threads. Actually I was
expecting to be in different ones - because it looks as if I am locking my
own thread with the mutex and the CLR is not getting me back to where I gave
up control.

The Managed ThreadId actually indicates that the event is fired under the ID
of the main thread I was running -> under debugger that is until the moment
when I put my main thread to sleep.

I guess the issue is in the Process event itself or the thread scheduler -
it just should not fire under the ID of the user thread. To me this looks
like a CLR issue.
Or is it legal for any same thread to be in two code places almost at the
same time?

Anyways, guess we've run out of options and I have to use my 'homebuilt'
mutex. Maybe one could write the event handler such that it propagates onward
by firing its own thread, but that's probably a bit of overkill then too. (I
tried btw. to create the Process that fires the events under a worker thread
as well - no change in deadlock.)

I can retry the same using a mutex tomorrow, I tried that before as I said
with the same resulting deadlock.

Maybe someone can pick this up from here and see what's going on inside?

br
Theo


From: Peter Duniho on
On 2007-11-06 15:23:01 -0800, tb2000 <tb2000(a)discussions.microsoft.com> said:

> Pete,
>
> thanks again, I had hoped my code snip was sufficient - if you could let me
> know what concisely ;-) you're looking for I'll be glad to post it.

"Concise" means that you post the bare minimum of code required to
demonstrate the problem. "Complete" means that you post _everything_
that is required to demonstrate the problem. Someone should be able to
compile the code and run it, without any additions or changes, and
there should be nothing in the code that distracts or otherwise makes
it difficult to understand what's going on.

> The semaphore is doing exactly what I expected it to do: it prevents entry
> into the code while I was hoping I could release it when done in my main
> thread.

Well, for sure a semaphore won't work if both sections of code are run
in the same thread.

> Purpose was to synchronize two distinctly separate code blocks (so
> that only one can be in execution at the same time). I don't really care if I
> am in the same thread context or in different threads.

A thread can only execute one statement of code at a time. So if both
sections of code are running in the same thread, they are automatically
synchronized. You can be assured that if one somehow allows another to
execute, you aren't going to get back to the first section until the
second is done. If the second section waits on something that will
only be done by the first section, then yes...your code has essentially
deadlocked itself. It's not easy to do that with a single thread, but
a semaphore will.

Code executing in different threads can deadlock for real, but only if
they are waiting on each other. Deadlocking code is a sign of bad
design. The fix is to correct the design.

> Actually I was
> expecting to be in different ones - because it looks as if I am locking my
> own thread with the mutex and the CLR is not getting me back to where I gave
> up control.

You haven't posted enough code for anyone to comment on what's actually
happening. Suffice to say, the code you posted won't deadlock using a
mutex assuming it's all run in the same thread.

> The Managed ThreadId actually indicates that the event is fired under the ID
> of the main thread I was running -> under debugger that is until the moment
> when I put my main thread to sleep.
>
> I guess the issue is in the Process event itself or the thread scheduler -
> it just should not fire under the ID of the user thread. To me this looks
> like a CLR issue.

IMHO, it looks to me like a design problem in your own code. I'm not
really sure how the Process event deals with raising events, but I
suspect that what's going on is that the process event is raised once
the main thread enters what is called "an alertable wait state", in
which the OS can essentially run a callback within the same thread.
Calling Thread.Sleep() can do that. This is why the event is raised in
the same thread.

This is not "a CLR issue" so much as it is a symptom of a badly
designed piece of code. At a minimum, the attempt to synchronize is
wrong, and it may be that there is simply a better way to accomplish
whatever it is you are trying to accomplish.

Without a complete code sample, it's hard to see what is really trying
to be done here though. Also, you should be more clear about why it is
you feel these sections of code need to be synchronized. What are they
doing that conflict with each other?

> Or is it legal for any same thread to be in two code places almost at the
> same time?

It is not only illegal, it's impossible. Execution in a given thread
can take place only in a single spot in the code at any given time.

> Anyways, guess we've run out of options and I have to use my 'homebuilt'
> mutex.

I don't see how your "homebuilt mutex" changes any of the blocking
issues, and I definitely don't think it's the right solution in any
case.

> Maybe one could write the event handler such that it propagates onward
> by firing its own thread, but that's probably a bit of overkill then too. (I
> tried btw. to create the Process that fires the events under a worker thread
> as well - no change in deadlock.)
>
> I can retry the same using a mutex tomorrow, I tried that before as I said
> with the same resulting deadlock.
>
> Maybe someone can pick this up from here and see what's going on inside?

Maybe. But only if you post a concise-but-complete example of code
that reliably demonstrates the problem.

Pete

From: tb2000 on
Pete,
thanks for staying with this - here's the next attempt in being concise ;-)

This code is exactly the same sequence as in the one we discussed earlier,
interestingly this one works as one would expect - the event is raised in a
different thread, preventing the "self-deadlock".

The main difference seems to be - as far as I can tell - that the event is
appearing with its own thread idea and the main thread thus regains control
and continues (after the sleep() in ShellKill()). Now I have no idea how to
influence that nor do I understand why the event in my code is being raised
differently. I also tried the below code with the actual ssh etc code my
realworld app is using - but can not reproduce it either. You saw the process
ID.

Here's the console output where you can see that the main thread (ID10) is
actually continuing (back from sleep) while the event handler sits on the
lock.

-----------

Press CR to start kill shell process

ShellKill - Thread 10
ShellKill - Got lock - go for kill
ShellKill - CMD killed - wait here for event to happen
OnExited - Thread 13 - go for lock
ShellKill - back from sleep - releasing lock
OnExited - inside lock
OnExited - released lock
ShellKill - lock released
Press CR to exit

----------------------------

using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using System.Threading;

namespace Deadlock
{
class Deadlock
{
static Deadlock d = null;
static Process p;
static void Main(string[] args)
{
d = new Deadlock();
d.ShellStart();
Console.WriteLine("Press CR to start kill shell process");
Console.ReadLine();
d.ShellKill();
Console.WriteLine("Press CR to exit");
Console.ReadLine();
}

Semaphore s = new Semaphore(1,1);

private void ShellKill()
{
Console.WriteLine("ShellKill - Thread " +
Thread.CurrentThread.ManagedThreadId);
s.WaitOne();
Console.WriteLine("ShellKill - Got lock - go for kill");
if (p == null)
{
Console.WriteLine("ShellKill : Shell exited already");
}
else
{
//this is the ultimate abbreviation for simplicity of
demonstartion
//in my other code a .NET remote call to a remote process is
causing the
//remote side to exit - which will in sequence release CMD
(or ssh)
p.Kill();
Console.WriteLine("ShellKill - CMD killed - wait here for
event to happen");
//simulate some other cleanup work
Thread.Sleep(2000);
p = null;
Console.WriteLine("ShellKill - back from sleep - releasing
lock");
}
s.Release();
Console.WriteLine("ShellKill - lock released");
}

private void ShellStart()
{
string arg = "/c pause";
ProcessStartInfo psi = new ProcessStartInfo("cmd", arg);
p = new Process();
p.StartInfo = psi;
p.Exited += new EventHandler(OnExited);
p.EnableRaisingEvents = true;
p.Start();
}

void OnExited(object sender, EventArgs e)
{
Console.WriteLine("OnExited - Thread " +
Thread.CurrentThread.ManagedThreadId + " - go for lock");
s.WaitOne();
Console.WriteLine("OnExited - inside lock");
//dispose process (and other resources)
p = null;
s.Release();
Console.WriteLine("OnExited - released lock");
}
}
}

 |  Next  |  Last
Pages: 1 2 3
Next: In-Memory Assemblies