Imagine this snippet:
using System;
public class Report {
static int Level=0;
public static void WriteLine(string Message) {
Console.WriteLine("{0}{1}",new String(' ',4*Level),Message);
}
public class Indent:IDisposable {
public Indent() { Report.WriteLine("{"); ++Level; }
void IDisposable.Dispose() { --Level; Report.WriteLine("}"); }
}
}
class Program {
static void Main() {
Report.WriteLine("Started");
Report.WriteLine("Calling submethod");
using(new Report.Indent()) {
Report.WriteLine("Submethod started");
using(new Report.Indent()) Report.WriteLine("Subsub, maybe?");
Report.WriteLine("Submethod reporting everything is fine");
Report.WriteLine("Submethod finished");
}
Report.WriteLine("Finished");
}
}
Which produces result:
Started
Calling submethod
{
Submethod started
{
Subsub, maybe?
}
Submethod reporting everything is fine
Submethod finished
}
Finished
Inside I'm using using(new Report.Indent()) instead of sticking to the only documented version I found, i.e. using(Report.Indent r=new Report.Indent()).
In my briefer version, however, can I be sure that Dispose() will always be called on those unnamed Indent objects, every time?
P.S.
// btw, I used word "anonymous" in the title, but I'm not sure that's what new objects that aren't assigned to any named variable should be called
Yes, using enures that even "anonymous objects" are always disposed of.
Internally, using stores whatever value was used when entering the block in local variable. This stored value is disposed when exiting the block.
Related
I read the book "CLR via C#" by Jeffrey Richter. In chapter 20, there is a code example demonstrating usage of Constrained Execution Regions (CERs):
private static void Demo2() {
// Force the code in the finally to be eagerly prepared
RuntimeHelpers.PrepareConstrainedRegions(); // System.Runtime.CompilerServices namespace
try {
Console.WriteLine("In try");
}
finally {
// Type2’s static constructor is implicitly called in here
Type2.M();
}
}
public class Type2 {
static Type2() {
Console.WriteLine("Type2's static ctor called");
}
// Use this attribute defined in the System.Runtime.ConstrainedExecution namespace
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
public static void M() { }
}
And the following text:
Now, when I run this version of the code, I get the following output.
Type2's static ctor called
In try
But when I run this code I get the following output no matter if I use CERs or not:
In try
Type2's static ctor called
So, Type2 constructor is getting called after try block (breaking the meaning of CERs usages, as I understand it).
What can be possible reason of this?
EDIT:
I'm using .Net Core 3.1 and VS Enterprise 2019 Preview
Version 16.6.0 Preview 3.0, my code is:
using System;
using System.Runtime.CompilerServices;
using System.Runtime.ConstrainedExecution;
public sealed class Program
{
public static void Main()
{
Demo2();
}
private static void Demo2()
{
RuntimeHelpers.PrepareConstrainedRegions();
try
{
Console.WriteLine("In try");
}
finally
{
Type2.M();
}
}
}
public class Type2
{
static Type2()
{
Console.WriteLine("Type2's static ctor called");
}
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
public static void M() { }
}
By the way, Type2 class can be inside the Program, it does not change the output.
(This is not the full answer to what is actually going on here, but it might help you)
Your problem is most likely that you run your process from within Visual Studio (using CTRL+F5). It is then launched via VsDebugConsole.exe, which then starts your process (also see this).
For whatever reason - that would need to be researched - it looks as if CERs are not honored when running in this way.
What you could do to validate, is attempt to run your program directly from the command prompt / console.
Here is a quote from Microsoft's article about Constrained Execution Regions:
CER is only supported in .NET Framework. This article doesn't apply to
.NET Core or .NET 5 and above.
im trying some different approach. Im not sure if its possible to place using() statement above methods or is there other way around.
public class Main
{
public Main()
{
using(Type t = new Type)
{
public void SomeFunction() {
t.toString()}
}
}
}
That is not possible, but you can do that like this:
using(Type t = new Type)
{
SomeFunction(t);
}
public void SomeFunction(Type tType)
{
tType.ToString();
}
Note : The t will be transferred to SomeFunction() and will be disposed at } of using block if the Class Type implements IDisposible, Since Using statement calls the Dispose method on the object in the correct way, and (when you use it as shown earlier) it also causes the object itself to go out of scope as soon as Dispose is called
I've been struggling with an issue that recently popped up with a simple logtofile class I wrote.
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
namespace Assets.Code
{
class TimingLogger
{
public static readonly TimingLogger Logger = new TimingLogger();
private static readonly string path = "C:\\Logs\\TimingLog.txt";
private readonly Mutex mutex = new Mutex(false, path);
private StreamWriter writer;
private readonly Queue<string> queue = new Queue<string>();
private bool isRunning;
private readonly object obj = new object();
private TimingLogger()
{
}
public void CheckPath()
{
if (!File.Exists(path))
{
File.Create(path);
}
}
public void Run()
{
isRunning = true;
while (isRunning)
{
lock (obj)
{
while (queue.Count <= 0)
{
Monitor.Wait(obj);
}
Log(queue.Dequeue());
}
}
}
public void Log(string line)
{
try
{
mutex.WaitOne();
writer = File.AppendText(path);
writer.WriteLine(line);
writer.Close();
}
catch (Exception)
{
//throw;
}
finally
{
mutex.ReleaseMutex();
}
}
public void Enqueue(string line)
{
lock (obj)
{
queue.Enqueue(line);
Monitor.Pulse(obj);
}
}
public void Stop()
{
isRunning = false;
}
}
}
This class was working just fine until recently, when I noticed that my log file wasn't showing the data I expected. Strangely enough, I hadn't changed any functionality of the class. Comparing an old, working version with my new one, the only difference was that some of my fields were made private and readonly. Besides that, the string path was changed to const. And to my complete bewilderment, changing this back to readonly fixed the issue I was having.
So my question is: How on earth is this possible? As far as I'm aware, there shouldn't functionally be any difference between readonly and const in this situation.
When debugging, the change in behavior is substantial, especially in the Run() method. What should happen here is that once Log(queue.Dequeue()); has been called, the thread will leave the lock statement and iterate through the while (isRunning) loop again. This seems pretty obvious, right? However, when I change the string path to const and debug again, the Log(queue.Dequeue()); is passed once and a single statement can be found in the log file, after which it simply doesn't do anything else ever again. It doesn't come past while (isRunning) again and it doesn't seem to leave the lock (obj) block. The logger thread seems to simply shutdown or pause after successfully calling Log(queue.Dequeue()); once.
Actually throwing the exception in the Log method makes no difference, no exceptions are thrown because the logging itself works fine.
I should mention that I'm using this code with Unity3D 5, which uses Mono. But still, this drastic change in behavior by such a small edit seems impossible to me. Can anyone explain why this is happening?
Thanks!
Here is the difference:
Consts are created in the metadata of the files, so when you run you class the value is already there.
ReadOnly are initialized in compile time, in your case, heres the trick, even though you declared path first then the mutex, the compiler initialized the mutex object first, here is why:
Your first static object to be initialized is the Logger:
public static readonly TimingLogger Logger = new TimingLogger();
Because you called the constructor, the non static members are initialized, making mutex the next member to be initialized. At this point you didnt initialized path yet, so
you are creating your mutex object with parameters false and null.
If you want to have the same error that you have with const using readonly, you can force the order of your static parameters initialization using a static constructor like :
static TimingLogger()
{
path = "C:\\Logs\\TimingLog.txt";
Logger = new TimingLogger();
}
Or simply putting path before Logger.
If you don't want to have the error using const, just change the mutex initialization using null parameter:
private readonly Mutex mutex = new Mutex(false, null);
Im trying to hunt down a race condition, and I come across a lot of suspecious functions. Most of them are not allowed to be called from two threads at the same time, but its hard to make sure they don't.
Is there some keyword to instruct the runtime to throw an exception as soon as a function is executing in parallel? I know I sometimes get an exception when another thread modifies a collection which im enumerating, but are safeguards like that enough to rely on?
The runtime can halt execution using the lock instruction, so all I need is a lock which throws an error.
You can use Monitor.TryEnter for this:
bool entered = !Monitor.TryEnter(someLockObject);
try
{
if (!entered)
throw Exception("Multi-thread call!");
// Actual code
}
finally
{
if (entered)
{
Monitor.Exit(someLockObject);
}
}
And it would be good to wrap that code in its own class:
public sealed class MultiThreadProtector : IDisposable
{
private object syncRoot;
public MultiThreadProtector(object syncRoot)
{
this.syncRoot = syncRoot;
if (!Monitor.TryEnter(syncRoot))
{
throw new Exception("Failure!");
}
}
public void Dispose()
{
Monitor.Exit(this.syncRoot);
}
}
This way you can execute it as follows:
using (new MultiThreadProtector(someLockObject))
{
// protected code.
}
Since we register the callback function PrintOne twice, the following code will print the message "PrintOne" twice. Here are questions,
Question 1> Why by default the operator+=(i.e. Combine) doesn't check duplicate method handler?
Question 2> How to avoid this duplicated call in method RegisterCall? I try to find some method in MulticastDelegate/Delegate that can tell me there is already one in the calling list. But I didn't find it.
http://msdn.microsoft.com/en-us/library/system.multicastdelegate.aspx
Thank you
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace app3
{
class Car
{
public delegate void PrintMethod(string msg);
public string Name { get; set; }
private PrintMethod printMethods;
public Car() { }
public Car(string name) { Name = name; }
public void PrintCar()
{
if (printMethods != null)
{
printMethods(this.ToString());
}
else
{
Console.WriteLine("No Method will be called");
}
}
public override string ToString()
{
return string.Format("Car Name is {0}: ", Name);
}
public static void PrintOne(string msg)
{
Console.WriteLine("PrintOne");
}
public static void PrintTwo(string msg)
{
Console.WriteLine("PrintTwo");
}
public void RegisterCall(PrintMethod methodToCall)
{
printMethods += methodToCall;
}
}
class Program
{
static void Main(string[] args)
{
Car mycar = new Car { Name = "BMW" };
mycar.RegisterCall(new Car.PrintMethod(Car.PrintOne)); // **will print for the first time**
mycar.RegisterCall(new Car.PrintMethod(Car.PrintOne)); // **will print for the second time**
mycar.PrintCar();
Console.ReadLine();
}
}
}
public void RegisterCall(PrintMethod methodToCall)
{
printMethods -= methodToCall;
printMethods += methodToCall;
}
This will make sure it is removed if present in the multicast delegate, then added, to ensure 1 instance.
Adding a handler doesn't abort if a delegate to the same handler is already present in the multicast delegate because most of the time duplicates don't happen. There are also valid situations in which calling the same method twice is what is wanted (such as custom aggregation on an object or collection).
If they had decided that duplication would be avoided, they would have to throw an exception when adding the handler. That's expensive in a number of ways, both when they occur at runtime and in all the ugly try-catch blocks we'd have to write.
The typical design for registered callbacks in C# is to put a public event on your object. This way another class can add and—just as importantly—remove event handlers. It is not clear to me why you are using a RegisterCall method rather than using the built-in event registration features of C#.
Normally, the module that adds an event handler to an event will also remove that handler when the call is no longer needed. This is required for any event-handling object that has an expected lifetime of shorter duration than the event-generating object itself, since delegates hold references to the object instances and will keep them alive.