In the past, I've been burned by the "side-effects-in-an-accessor" issue when debugging; meaning that I've had caches being initialised without my breakpoints being triggered (since it was already paused in visual studio). And so I've been wondering about the mechanism that Visual Studio uses to execute code "out-of-order", so as to evaluate properties in a debugger. It would seem to me that this would circumvent the CLR?
So the question: How is this done from a technical standpoint? Articles explaining it would be helpful.
Looks like VS2012 (and probably earlier versions as well) executes the property's getter using the "Main Thread" or maybe the thread that hit the breakpoint.
This is my testing code:
static class TestSideEffects
{
public static void Test()
{
Console.WriteLine("Main Thread: {0}", Thread.CurrentThread.ManagedThreadId);
var o = new TestSubject();
Console.WriteLine("Property Value: {0}", o.IntGetValueNoSe());
}
}
class TestSubject
{
private int _prop=0;
public int TheProperty
{
get
{
Console.WriteLine("Thread accessing the property: {0}", Thread.CurrentThread.ManagedThreadId);
return ++_prop;
}
}
public int IntGetValueNoSe(){return _prop; }
}
I set two breakpoints: on the 3rd line of the Test method and in the getter itself, and every time I hover my mouse over the o instance - it executes the getter without triggering the other breakpoint. It uses the same (main in this case) thread.
This is the output of the test program:
Main Thread: 8
Thread accessing the property: 8
Thread accessing the property: 8
Thread accessing the property: 8
Related
I am using MonoDevelop with GTK Sharp 2.12. I have set this up using the default GTK Sharp windowed project. Add a button, add a button-click event and placed the following code:
protected async void OnBtnTest(object sender, EventArgs e)
{
Debug.WriteLine($"Before: {Thread.CurrentThread.ManagedThreadId}");
await Task.Delay(2000);
Debug.WriteLine($"After: {Thread.CurrentThread.ManagedThreadId}");
using (var msg = new MessageDialog(this, DialogFlags.Modal,
MessageType.Info, ButtonsType.Ok, "CRASH"))
{
msg.Run();
msg.Destroy();
}
}
The output is:
Before: 1
Started Thread 27672
After: 4
(TestSyncContext:26912): Gdk-CRITICAL **: gdk_window_set_geometry_hints: assertion 'GDK_IS_WINDOW (window)' failed
The "critical" line is a crash in the program -- This is because the UI thread didn't return when continuing on to show the MessageDialog. You can see the managed thread ID changed after the call to await.
Puzzled by this, I started researching and found this bit of code from a long, long time ago; Specifically these lines caught my attention:
gtk_init (ref argc, ref argv);
SynchronizationContext.SetSynchronizationContext (new GLib.GLibSynchronizationContext ());
So I started to wonder: Does GTK Sharp not set up a synchronization context by default?
I decided to throw it in the code, but GLib.GLibSynchronizationContext() does not exist in the GLib library.
OK, that's odd -- I searched for that on the web and found the source code to that object; Copied and pasted it in to my project, then called it as so:
class MainClass
{
public static void Main(string[] args)
{
Application.Init();
SynchronizationContext.SetSynchronizationContext(new GLibSynchronizationContext());
MainWindow win = new MainWindow();
win.Show();
Application.Run();
}
}
Ran it again, and it performs how I would have expected it to without adding a context:
Before: 1
Started Thread 22744
After: 1
No crashes. UI thread came back to continue on down the method.
My questions are:
Did GTK Sharp intentionally not include a synchronization context in their UI framework on purpose?
Did GTK Sharp intentionally not attempt to initialize a sync-ctx on purpose? Meaning they never intended it to work with the async/await pattern by default?
Why is GLib.GLibSynchronizationContext no longer available?
Is what I did to fix it the correct way to add a proper sync-ctx to GTK Sharp?
I have production code with this fix going out, and I want to make sure that what I did isn't unorthodox. OR: maybe there is a better way to set up GTK Sharp to handle the async/await pattern that isn't very well documented.
I am getting an undefined null pointer exception if I try this. (Removing the thread code solves it). Isn't it possible to spawn a new thread from a setter? If so, why not? I am used to doing it this way from Java. Thank you
EDIT: The actual stripped down code:
public string AuthToken {
set {
this.authToken = value;
var RunOnNewThread = new Thread(() =>
{
Console.WriteLine("Test");
} );
RunOnNewThread.Start();
}
get { return this.authToken; }
}
It does actually run the thread. Note! This is in an Xamarin Android app, and the error only occurs in debug mode. Release works perfectly.
Thread started: #2 Test Thread finished: #2
Here a screenshot from Xamarin:
I tried surrounding the thread creation in a try/catch, but it still throws the null pointer on RunOnNewThread.Start().
However, there must be something else going on. Because it just ran fine 2 times, and the 3rd time I got the null pointer again. Any ideas?
I'm writing a debugger extension VSPackage in which I want to execute a statement in the debugged process when a breakpoint is hit. In my extension code I have this:
void Initialize()
{
// ...standard vspackage init code omitted...
Globals.Init((DTE2)GetService(typeof(DTE)));
Globals.DebuggerEvents.OnEnterBreakMode += (dbgEventReason reason, ref dbgExecutionAction action) =>
{
try
{
var e1 = Globals.Application.Debugger.GetExpression("1+2");
Debug.WriteLine(e1.Value); // Prints "3"
Globals.Application.Debugger.ExecuteStatement("x = 1+2", 1000);
Debug.WriteLine("OK"); // Never prints this
}
catch (Exception ex)
{
Debug.WriteLine("Error: "+ex); // Nor this
}
}
}
When debugging this extension in a VS instance I load a trivial program looking like this
static void Main()
{
int x = 5;
Console.WriteLine("X is "+x); // Breakpoint on this line
}
When the breakpoint is hit in the debugged process the handler is called and the output window for the extension shows "3", so evaluating expressions works, but it never succeeds executing the statement. Nothing more is printed to the output window. No exception or timeout occurs and I can't continue debugging the process, the debugger appears to have crashed.
The globals class just holds the DTE and DebuggerEvents
public static class Globals
{
public static void Init(DTE2 dte)
{
Application = dte;
DebuggerEvents = dte.Events.DebuggerEvents;
}
public static DTE2 Application { get; private set; }
public static DebuggerEvents DebuggerEvents { get; private set; }
}
What am I doing wrong, or misunderstanding here?
This is an old question, but there is so little on Google about these issues, I thought I'd offer some help. Some important considerations:
Use GetExpresssion3(TreatAsStatement:=True), if possible, instead of ExecuteStatement (I could not get ExecuteStatement working properly).
The thread calling your delegate (OnEnterBreakMode) is the same thread that will need will to run again in order to execute your expression or statement. Therefore, call your GetExpression method on a new thread (Task.Run..)
You will have to monitor and manage the Reason value for OnEnterBreakMode. The initial Reason is UnwindFromException for the actual unhandled exception. Then, it is expected you are setting a variable, such as tempStack = New System.Diagnostics.StackTrace(True). OnEnterBreakMode will be called again following execution of this statement, but this time with Evaluation for the Reason. At this point you now call all of your GetExpressions to collect all of your data without additional OnEnterBreakMode calls.
Dim dte2 As EnvDTE80.DTE2 = GetGlobalService(GetType(EnvDTE.DTE))
Dim debugger5 as EnvDTE100.Debugger5 = Dte2.Debugger
Interesting design observation: System.Diagnostics.StackTrace is a very strangely designed class in the context of the rest of the .NET framework until you have to work on this project where you are extracting the StackTrace through this very technique and see the benefit of its otherwise odd design.
I was tinkering a lot with Visual Studio debugging, and the ultimate cause of freezing was always related to thread handling: VS allows any piece of code to run while debugging only in the main thread. Every other thread is disabled and in case your debug code depends on a different thread it will freeze too.
My guess: You initialized your DTE in a different thread than what you are debugging.
Assumed result: Delegate method tries to load the context of the initializing thread which is different from the debugged thread, and thus it is bound to get frozen.
Proposed solution: Don't use delegate method. They implicitly refer back to the original execution context. Instead register a regular method, and reinitialize your DTE in that context.
I'm working in C# 4.0 (winforms), debugging an application with 10+ threads. While debugging, there is a drop down to select which thread I should be debugging (only accessible during a breakpoint).
These show up as "Win32 Thread", "Worker Thread", "RPC Callback Thread", etc...
I'd love to name them from within my code. I'm running all my threads via background workers.
Edit: my solution. This may not work 100% of the time, but it does exactly what it needs to. If the labels are wrong in some case, thats OK in the context I'm working with.
At every backgroundworker's *_dowork event, I put the following line of code in:
ReportData.TrySetCurrentThreadName(String.Format("{0}.{1}", MethodBase.GetCurrentMethod().DeclaringType, MethodBase.GetCurrentMethod().Name));
Which is...
public static void TrySetCurrentThreadName(String threadName)
{
if (System.Threading.Thread.CurrentThread.Name == null)
{
System.Threading.Thread.CurrentThread.Name = threadName;
}
}
Well you can use the Thread.Name property, but you can only write to it once - so when you create the thread, give it an appropriate name.
Thread.CurrentThread.Name = "Give your name here";
I came across this situation where the following plinq statement inside static constructor gets deadlocked:
static void Main(string[] args)
{
new Blah();
}
class Blah
{
static Blah()
{
Enumerable.Range(1, 10000)
.AsParallel()
.Select(n => n * 3)
.ToList();
}
}
It happens only when a constructor is static.
Can someone explain this to me please.
Is it TPL bug? Compiler? Me?
It is generally dangerous to call threading code from a static constructor. In order to ensure that the static constructor executes only once, the CLR executes the static constructor under a lock. If the thread running the static constructor waits on a helper thread, there is a risk that the helper thread is going to need the CLR-internal lock for some reason too, and the program will deadlock.
Here is a simpler code sample that demonstrates the problem:
using System.Threading;
class Blah
{
static void Main() { /* Won’t run because the static constructor deadlocks. */ }
static Blah()
{
Thread thread = new Thread(ThreadBody);
thread.Start();
thread.Join();
}
static void ThreadBody() { }
}
Section 10.5.3.3 "Races and deadlocks" of the ECMA CLI spec guarantees the following:
Type initialization alone shall not create a deadlock unless some code
called from a type initializer (directly or indirectly) explicitly
invokes blocking operations.
So, a type initializer (i.e., a static constructor) will not deadlock, provided that no operation in the static constructor blocks the thread. If the static constructor does block, it risks a deadlock.
While the reason has already been explained as to why you wouldn't want to do threaded work inside a static constructor, I thought I'd add that the "right" way to do this instead would be with a static Lazy<T>. This is also more efficient as the work to generate those resources will be defferred until those resources are actually needed.
class Blah
{
// Supply factory method to generate the numbers, but actual generation will be deferred
private static Lazy<List<int>> MyMagicNumbers = new Lazy<List<int>>(Blah.GenerateMagicNumbers);
public void DoSomethingWithMagicNumbers()
{
// Call to Lazy<T>.Value will synchronize any calling threads until value is initially generated from the factory
List<int> magicNumbers = Blah.MyMagicNumbers.Value;
// ... do something here ...
}
private List<int> GenerateMagicNumbers()
{
return Enumerable.Range(1, 10000)
.AsParallel()
.Select(n => n * 3)
.ToList();
}
}
For what its worth, the issue does not arise on Mono:
[mono] /tmp # dmcs par.cs
[mono] /tmp # mono ./par.exe
Do you have a windows compiled binary so I can compare the generated MSIL? I'm not convinced this is a library-only issue, and I'm curious :)
Comparing the IL was a bit messy, so I decided to just try both binaries on both platforms.
Hehe I revived my old Windows virtual machine just to test this :)
Running the VS compiled binaries on Mono is no problem. You could try it on windows using 2.10.1 (http://www.go-mono.com/mono-downloads/download.html), only 77.4Mb :)
(I used a custom built mono 2.11 on linux so it could be that the feature support is not complete yet)
\ run on platform: MS.Net 4.0 Mono 2.1x
built on: -------------+----------------------------------------
Visual Studio | deadlock no deadlock
|
MonoDevelop | deadlock no deadlock
I also noticed that when running on windows, a CTRL-C is able to break out of the lock.
Will post if I find some more to this.
Update 2
Well, installing Mono runs circles around installing installing VSExpress even on windows. Installing mono has finished in 4 minutes, and resulted in:
C:\Users\Seth>"c:\Program Files (x86)\Mono-2.10.1\bin\mono.exe" ConsoleApplication2.exe
C:\Users\Seth>
No deadlock :) Now all that remains is waiting for VSExpress to be installed (forever) and istall debugging tools (unknown) and than have a crack at it (probably till late night). CU later