C# Getter-Setter Race Conditions - c#

Suppose I have two threads, thread A and thread B. What happens in C# when thread A sets an object, call it object X, to a value, and thread B comes along and tries to fetch that object while it is getting set by thread A? Would C# throw an exception, would B receive object X before A makes changes to it, or would B receive object X after A makes changes to it?
I thought it was clear, but here is the code (and even with added synchronization I am still not 100% sure that this would cause the exact case I mentioned above to occur):
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
namespace WindowsFormsApplication8 {
public partial class Form1 : Form {
private AutoResetEvent waitEvent = new AutoResetEvent(false);
int objectX = 0;
public Form1() {
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e) {
DateTime startTime = DateTime.Now;
Console.WriteLine("---------------------------- START # " + startTime + " ----------------------------------------------------------------------");
Thread A = new Thread(ThreadAWorkMethod);
Thread B = new Thread(ThreadBWorkMethod);
objectX = 0;
waitEvent = new AutoResetEvent(false);
A.Start();
B.Start();
A.Join();
B.Join();
Console.WriteLine("---------------------------- FINISHED AFTER " + (DateTime.Now - startTime).TotalMilliseconds + " ----------------------------");
}
public void ThreadAWorkMethod() {
waitEvent.WaitOne();
objectX = 5;
Console.WriteLine("Value has been changed to: " + objectX + " in thread A at " + DateTime.Now);
return;
}
public void ThreadBWorkMethod() {
waitEvent.Set();
string xInThreadB = objectX.ToString();
Console.WriteLine("Value in thread B: " + xInThreadB + " at " + DateTime.Now);
return;
}
}
}
The output of thread B to the console looks to be either 0 or 5, but even still you cannot say for certain which thread got serviced first even by checking the DateTime because both threads will have identical timestamps...and one output always makes it to the console first, so whose to say which got serviced first and if the threads actually collided on a get-set. So, in the end it seems that locking is implemented on variables in C# from a lower framework level as some people have mentioned.

Would C# throw an exception
No, it will likely not. There is nothing in the runtime that will check for this condition automatically and raise an exception.
However, the "value" being set may or may not be in a valid state at that point, so as soon as the result is used, whatever uses the value could easily raise an exception.
would B receive object X before A makes changes to it, or would B receive object X after A makes changes to it?
Either is possible. It's also possible, depending on the type of "object", that B would receive the object in an invalid state.
If you know multiple threads will be accessing a value, you should always take care to synchronize the access to your property. There are many options for synchronization, from using the (relatively) simple lock statement to other more complex synchronization options (such as ReaderWriterLock/ReaderWriterLockSlim, Mutex, Semaphore, etc).

So, something like this?
public class Test
{
public Test()
{
DateTime now = DateTime.Now;
Debug.WriteLine("Test started.");
A.Start();
B.Start();
A.Join();
B.Join();
Debug.WriteLine("Total time, in milliseconds, that you just spent in order to save StackOverflow members several minutes of their time: " + (DateTime.Now - now).TotalMilliseconds + " :)");
}
int objectX = 0;
Thread A = new Thread(ThreadAWorkMethod);
Thread B = new Thread(ThreadBWorkMethod);
public void ThreadAWorkMethod()
{
objectX = 5;
Debug.WriteLine("Value has been changed to: " + objectX.ToString() + "at " DateTime.Now.Milliseconds);
return;
}
public void ThreadBWorkMethod()
{
string xInThreadB = objectX.ToString();
Debug.WriteLine("Value in thread b: " + xInThreadB + "at " DateTime.Now.Milliseconds);
return;
}
}
I dunno, try it :)

Potentially similar question to C# Threading: a race condition example.
PS: That's why there is the lock and mutex in .NET Framework.

Related

C# static function is sending wrong arguments to function

My code is passing the wrong argument to a function for some reason.
I have a static class say class A having this function AddMaster :
public static void AddMaster(string ipAddress, int port, List<RegisterMap> registers)
{
// THIS LINE PRINTS THE ACTUAL VALUES SENT FROM THE CALLER FUNCTION
System.IO.File.AppendAllText("datalog_MB.txt", ipAddress + " " + registers[0].FriendlyName + "\n");
new Thread(() =>
{
_tasks.Add(Task.Factory.StartNew(() =>
{
Monitor.Enter(_masters);
_masters.Add(new Master().Connect(ipAddress, port).SetRegisters(registers));
_masters.Last().OnEvent += MasterEvent;
Debug.WriteLine(_masters.Count + " TCP masters connected");
Monitor.Exit(_masters);
}));
}).Start();
}
I have another non-static class Master having the function SetRegisters:
public Master SetRegisters(List<RegisterMap> registerList)
{
// HERE THE FriendlyName ALWAYS PRINTS THE VALUE OF THE LAST FUNCTION CALL
System.IO.File.AppendAllText("datalog_MB_1.txt", _hostname + " " + registerList[0].FriendlyName + "\n");
_registersToRead = registerList;
return this;
}
The function AddMaster() is called in a loop.
The first code logs the following which is correct:
# datalog_MB.txt
192.168.0.12 192.168.0.12:Value 1
192.168.0.11 192.168.0.11:Value 1
However the second code block prints the following ( See the second value has changed ):
# datalog_MB_1.txt
192.168.0.12 192.168.0.11:Value 1
192.168.0.11 192.168.0.11:Value 1
Edit #1
foreach (var equipment in MSSQL.GetEquipments(true))
{
registers.Clear();
System.IO.File.AppendAllText("dataeq.txt", equipment.IPAddress + " " + equipment.Name + " " + equipment.ID + "\n");
try
{
registers.Add(
new RegisterMap
{
FriendlyName = equipment.IPAddress + ":Value 1",
Register = 2001,
Type = RegisterType.HoldingRegister,
StationID = 1
});
registers.Add(
new RegisterMap
{
FriendlyName = equipment.IPAddress + ":Value 2",
Register = 2002,
Type = RegisterType.HoldingRegister,
StationID = 1
});
A.AddMaster(equipment.IPAddress, 502, registers);
var json = new JavaScriptSerializer().Serialize(registers);
System.IO.File.AppendAllText("data_reg.txt", json + "\n\n");
}
catch(Exception err)
{
System.Windows.MessageBox.Show(err.Message);
}
}
Edit #2*
Fiddle: https://dotnetfiddle.net/h3yn7p
Any idea what might be going wrong?
You should not Clear the registers - recreate it:
List<RegisterMap> registers = null;
foreach(var equipment in equipments)
{
registers = new List<RegisterMap>();
....
}
Otherwise you are processing the same instance of List<RegisterMap> in parallel in multiple threads while manipulating it (i.e. thread which has the foreach(var equipment in equipments) loop will run and create all the threads and start them), which can lead to a lot of different concurrency issues.
Also some notes:
Consider using concurrent collections, for example ConcurrentBag<T> instead of Monitor + List (cause in current code it makes Thread/Task handling pointless)
Based on the provided code there is no need to create Thread - tasks should be enough. In modern .NET there is rarely a case when you need to create Threads manually, most of the time it is hugely discouraged (read more).

Update console text from multiple threads not working

I am executing/processing very big files in multi threaded mode in a console app.
When I don't update/write to the console from threads, for testing the whole process take about 1 minute.
But when I try to update/write to console from threads to show the progress, the process stuck and it never finishes (waited several minutes even hours). And also console text/window does not updated as it should.
Update-1: As requested by few kind responder, i added minimal code that can reproduce the same error/problem
Here is the code from the thread function/method:
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
namespace Large_Text_To_Small_Text
{
class Program
{
static string sAppPath;
static ArrayList objThreadList;
private struct ThreadFileInfo
{
public string sBaseDir, sRFile;
public int iCurFile, iTFile;
public bool bIncludesExtension;
}
static void Main(string[] args)
{
string sFileDir;
DateTime dtStart;
Console.Clear();
sAppPath = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
sFileDir = #"d:\Test";
dtStart = DateTime.Now;
///process in multi threaded mode
List<string> lFiles;
lFiles = new List<string>();
lFiles.AddRange(Directory.GetFiles(sFileDir, "*.*", SearchOption.AllDirectories));
if (Directory.Exists(sFileDir + "-Processed") == true)
{
Directory.Delete(sFileDir + "-Processed", true);
}
Directory.CreateDirectory(sFileDir + "-Processed");
sPrepareThreading();
for (int iFLoop = 0; iFLoop < lFiles.Count; iFLoop++)
{
//Console.WriteLine(string.Format("{0}/{1}", (iFLoop + 1), lFiles.Count));
sThreadProcessFile(sFileDir + "-Processed", lFiles[iFLoop], (iFLoop + 1), lFiles.Count, Convert.ToBoolean(args[3]));
}
sFinishThreading();
Console.WriteLine(DateTime.Now.Subtract(dtStart).ToString());
Console.ReadKey();
return;
}
private static void sProcSO(object oThreadInfo)
{
var inputLines = new BlockingCollection<string>();
long lACounter, lCCounter;
ThreadFileInfo oProcInfo;
lACounter = 0;
lCCounter = 0;
oProcInfo = (ThreadFileInfo)oThreadInfo;
var readLines = Task.Factory.StartNew(() =>
{
foreach (var line in File.ReadLines(oProcInfo.sRFile))
{
inputLines.Add(line);
lACounter++;
}
inputLines.CompleteAdding();
});
var processLines = Task.Factory.StartNew(() =>
{
Parallel.ForEach(inputLines.GetConsumingEnumerable(), line =>
{
lCCounter++;
/*
some process goes here
*/
/*If i Comment out these lines program get stuck!*/
//Console.SetCursorPosition(0, oProcInfo.iCurFile);
//Console.Write(oProcInfo.iCurFile + " = " + lCCounter.ToString());
});
});
Task.WaitAll(readLines, processLines);
}
private static void sPrepareThreading()
{
objThreadList = new ArrayList();
for (var iTLoop = 0; iTLoop < 5; iTLoop++)
{
objThreadList.Add(null);
}
}
private static void sThreadProcessFile(string sBaseDir, string sRFile, int iCurFile, int iTFile, bool bIncludesExtension)
{
Boolean bMatched;
Thread oCurThread;
ThreadFileInfo oProcInfo;
Salma_RecheckThread:
bMatched = false;
for (int iTLoop = 0; iTLoop < 5; iTLoop++)
{
if (objThreadList[iTLoop] == null || ((System.Threading.Thread)(objThreadList[iTLoop])).IsAlive == false)
{
oProcInfo = new ThreadFileInfo()
{
sBaseDir = sBaseDir,
sRFile = sRFile,
iCurFile = iCurFile,
iTFile = iTFile,
bIncludesExtension = bIncludesExtension
};
oCurThread = new Thread(sProcSO);
oCurThread.IsBackground = true;
oCurThread.Start(oProcInfo);
objThreadList[iTLoop] = oCurThread;
bMatched = true;
break;
}
}
if (bMatched == false)
{
System.Threading.Thread.Sleep(250);
goto Salma_RecheckThread;
}
}
private static void sFinishThreading()
{
Boolean bRunning;
Salma_RecheckThread:
bRunning = false;
for (int iTLoop = 0; iTLoop < 5; iTLoop++)
{
if (objThreadList[iTLoop] != null && ((System.Threading.Thread)(objThreadList[iTLoop])).IsAlive == true)
{
bRunning = true;
}
}
if (bRunning == true)
{
System.Threading.Thread.Sleep(250);
goto Salma_RecheckThread;
}
}
}
}
And here is the screenshot, if I try to update console window:
You see? Nor the line number (oProcInfo.iCurFile) or the whole line is correct!
It should be like this:
1 = xxxxx
2 = xxxxx
3 = xxxxx
4 = xxxxx
5 = xxxxx
Update-1: To test just change the sFileDir to any folder that has some big text file or if you like you can download some big text files from following link:
https://wetransfer.com/downloads/8aecfe05bb44e35582fc338f623ad43b20210602005845/bcdbb5
Am I missing any function/method to update console text from threads?
I can't reproduce it. In my tests the process always runs to completion, without getting stuck. The output is all over the place though, because the two lines below are not synchronized:
Console.SetCursorPosition(0, oProcInfo.iCurFile);
Console.Write(oProcInfo.iCurFile + " = " + lCCounter.ToString());
Each thread of the many threads involved in the computation invokes these two statements concurrently with the other threads. This makes it possible for one thread to preempt another, and move the cursor before the first thread has the chance to write in the console. To solve this problem you must add proper synchronization, and the easiest way to do it is to use the lock statement:
class Program
{
static object _locker = new object();
And in the sProcSO method:
lock (_locker)
{
Console.SetCursorPosition(0, oProcInfo.iCurFile);
Console.Write(oProcInfo.iCurFile + " = " + lCCounter.ToString());
}
If you want to know more about thread synchronization, I recommend this online resource: Threading in C# - Part 2: Basic Synchronization
If you would like to hear my opinion about the code in the question, and you don't mind receiving criticism, my opinion is that honestly the code is so much riddled with problems that the best course of action would be to throw it away and restart from scratch. Use of archaic data structures (ArrayList???), liberal use of casting from object to specific types, liberal use of the goto statement, use of hungarian notation in public type members, all make the code difficult to follow, and easy for bugs to creep in. I found particularly problematic that each file is processed concurrently with all other files using a dedicated thread, and then each dedicated thread uses a ThreadPool thread (Task.Factory.StartNew) to starts a parallel loop (Parallel.ForEach) with unconfigured MaxDegreeOfParallelism. This setup ensures that the ThreadPool will be saturated so badly, that there is no hope that the availability of threads will ever match the demand. Most probably it will also result to a highly inefficient use of the storage device, especially if the hardware is a classic hard disk.
Your freezing problem may not be C# or code related
on the top left of your console window, on the icon .. right click
select Properties
remove the option of Quick Edit Mode and Insert Mode
you can google that feature, but essentially manifests in the problem you describe above
The formatting problem on the other hand does seem to be, here you need to create a class that serializes writes to the console window from a singe thread. a consumer/producer pattern would work (you could use a BlockingCollection to implement this quite easily)

Control 'ZedGraphControl' accessed from a thread other than the thread it was created on

I'm using the ZedGraph library, but on a website rather than Web Forms application. Quick intro - the app gets data from a database, generates a graph, saves it as an image and then displays the image on a web page.
I have a GraphController class, which basically looks like this:
public class GraphController {
private static GraphController instance;
private static ZedGraph.ZedGraphControl graph;
protected GraphController() { }
public static GraphController Instance {
get {
if (instance == null){
instance = new GraphController();
}
return instance;
}
}
public string GenerateGraph(Dictionary<DateTime, float> graphData, DataRow details, string graphType) {
if ((graph == null) || (graph.IsDisposed == false)) {
graph = new ZedGraph.ZedGraphControl();
}
graph.GraphPane.Title.IsVisible = false;
// function calls to generate graph. Graph object is referenced in these.
return SaveGraphAsImage(0000, graphType);
}
private void AddGridLines() {
// example of graph reference
graph.GraphPane.XAxis.MajorGrid.IsVisible = true;
}
private string SaveGraphAsImage(string paramId, string graphType) {
// Should deal with save location here
string location = HttpRuntime.AppDomainAppPath + "Graphs\\" + DateTime.Now.ToString("dd-MM-yyyy");
string filename = DateTime.Now.ToString("dd-MM-yyyy-HH-mm-ss-") + graphType + "-" + paramId + ".png";
if(System.IO.Directory.Exists(location) == false){
System.IO.Directory.CreateDirectory(location);
}
graph.Refresh();
try {
using (graph) {
string outputFileName = location + "\\" + filename;
if (File.Exists(outputFileName) == false) {
Bitmap image = graph.GraphPane.GetImage(960, 660, 180);
image.Save(outputFileName, ImageFormat.Png);
image.Dispose();
}
}
graph = null; // double check that it is removed.
return "../Graphs/" + DateTime.Now.ToString("dd-MM-yyyy") + "/" + filename;
}
catch (Exception ex) {
log("An error occured generating a graph. \n\n Error message: \n " + ex.Message + " \n\n Stack trace: \n " + ex.StackTrace);
graph = null;
return "#";
}
}
}
I've reduced it as much as possible, but it should show how the ZedGraph object is created, used and removed.
I've already tried some memory enhancements, getting rid of the graph object where possible, and trying the using(){} process to hopefully automatically remove it, but would welcome further suggestions.
My aim here is to improve memory management and reduce these errors. Running local performance tests, I get quite a few Control 'ZedGraphControl' accessed from a thread other than the thread it was created on. errors. I'm relatively new to threading, so I'm not sure if a) it is something that is needed here, or b) there's something that can be done to disable the possibility, or a better management of the graph object to ensure it is always within the same thread?
Edit: This GraphController is first called from an .aspx.cs page with the following: GraphController.GraphController.Instance.GenerateGraph(data, details, "graph-type");
Second Edit: I have re-written the code to not have the ZedGraphControl as private static, but instead it is created within the GenerateGraph and then passed around where necessary. Testing this up to 1,000 users in 60 seconds looks to have removed the cross-thread issues - does this sound likely?
The issue here was the use of static variables. As pointed out by Henk Holterman in the comments, static variables stay alive as long as the application process is alive, and is separate from any/all user requests. So by having the ZedGraph object as a static variable it mean't that it was potentially still available to multiple requests without being cleared properly, running into memory and cross-threading issues.
The solution is to declare the ZedGraph instance within the first GenerateGraph function and to then pass the same object to each other function that used it. This ensures that it is the same object in the same thread that is accessed throughout the process.

Query inside a thread

I have 3 comboboxes that are loaded with data from LINQ queries on page load. The problem is that queries contain so much data that it causes Internet Explorer to stop responding for a bit more than a minute.
As there are 3 queries my idea is to put them in 3 different threads, but the problem is at the end the only thing I get is the error saying: "Both DataSource and DataSourceID are defined on 'cbOrganizator'. Remove one definition."
cbOrganizator is a combobox.
Here is the code:
protected void Page_Load(object sender, EventArgs e)
{
Bind();
}
public void Osobe()
{
PravosudnaAkademijaEntities db = new PravosudnaAkademijaEntities();
var osoba = from o in db.osobas
orderby o.osoba_prezime
select new { o.osoba_id, imePrezime = o.osoba_prezime + " " + o.osoba_ime + " | " + o.tijelo.tijelo_naziv + " | " + o.radno_mjesto.rm_naziv_m };
cbPolaznik.DataSource = osoba;
cbPolaznik.DataTextField = "imePrezime";
cbPolaznik.DataValueField = "osoba_id";
cbPolaznik.DataBind();
cbPolaznik.Items.Insert(0, " ");
cbPredavac.DataSource = osoba;
cbPredavac.DataTextField = "imePrezime";
cbPredavac.DataValueField = "osoba_id";
cbPredavac.DataBind();
cbPredavac.Items.Insert(0, " ");
cbAOM.DataSource = osoba;
cbAOM.DataTextField = "imePrezime";
cbAOM.DataValueField = "osoba_id";
cbAOM.DataBind();
cbAOM.Items.Insert(0, " ");
}
public void Tijela()
{
PravosudnaAkademijaEntities db = new PravosudnaAkademijaEntities();
var tijelo = from t in db.tijeloes
orderby t.tijelo_naziv
select new { t.tijelo_id, sve = t.tijelo_naziv + " | " + t.mjesto.zupanija_drzava.zupanija_naziv };
cbOrganizator.DataSource = tijelo;
cbOrganizator.DataTextField = "sve";
cbOrganizator.DataValueField = "tijelo_id";
cbOrganizator.DataBind();
cbOrganizator.Items.Insert(0, " ");
}
public void Bind()
{
Thread tOsobe = new Thread(Osobe);
tOsobe.Start();
Thread tTijela = new Thread(Tijela);
tTijela.Start();
}
I don't know what's wrong so any help would be appreciated. The primary idea is to separate queries into threads so if my approach is wrong please let me know.
You're starting threads but not giving them a chance to finish before the page is loaded. I don't know how that results in your particular error, but if your page loads before the thread is completed, then you definitely won't get results.
I really don't see how you'll be able to accomplish what you're trying to do without AJAX.
if you do really want to do it with threads i would suggest performing the query on the threadpool. you can abstract your method so that it is called in delegate of the threadpool method
so i would replace bind with
ThreadPool.QueueUserWorkItem(new WaitCallback(Osobe));
ThreadPool.QueueUserWorkItem(new WaitCallback(Tijela));
change signature of Osobe, and Tijela to acccept a Object
eg.public void Osobe(object a )
you will also need to marshal the call across the thread as i am not sure if webforms will accept if the binding is happening on another thread.
All said and done is still feel the ajax method is the best way forward.

Identify the thread which holds the lock

one of the threads in my application blocked at the following lock statement and resulted in a deadlock
void ExecuteCommand()
{
lock(this._lockinstance)
{
// do some operation
}
}
Is it possible to easily identify which thread is currently holding the lock?.. My application has more than 50 threads, which makes it difficult to go through each callstack using visual studio to locate the thread that holds the lock
Some sample code to try out:
class Test {
private object locker = new object();
public void Run() {
lock (locker) { // <== breakpoint here
Console.WriteLine(System.Threading.Thread.CurrentThread.ManagedThreadId);
}
}
}
Set a breakpoint on the indicated line. When it breaks, use Debug + Windows + Memory + Memory 1. Right click the window and choose "4-byte Integer". In the Address box, type &locker. The 2nd word is the thread ID of the thread that owns the lock. Step past the lock statement to see it change.
Beware that the number is the managed thread ID, not the operating system thread ID that you see in the Debug + Windows + Threads window. That kinda sucks, you probably should add some logging to your program that dumps the value of ManagedThreadId so you have a way to match the value to a thread. Update: fixed in later VS versions, the Debug > Windows > Threads debugger window now shows the ManagedThreadId.
Recently I was trying to determine what function was holding a lock and found the following very useful and had not seen in demonstrated anywhere before. I've placed it as an answer here in case others find it useful too.
Many of the other solutions posted earlier require writing a new class and then converting of all lock(blah) to BetterLock(blah) which is a lot of work for debugging and which you may not want in the production/shipped version of your code. Others required having the debugger attached which changes the code's timing and could obscure the issue.
Instead, try the following...
Original code:
object obj = new object();
lock(obj)
{
// Do stuff
}
Modified code for debugging:
object _obj = new object();
object obj
{
get
{
System.Diagnostics.StackFrame frame = new System.Diagnostics.StackFrame(1);
System.Diagnostics.Trace.WriteLine(String.Format("Lock acquired by: {0} on thread {1}", frame.GetMethod().Name, System.Threading.Thread.CurrentThread.ManagedThreadId));
return _obj;
}
}
// Note that the code within lock(obj) and the lock itself remain unchanged.
lock(obj)
{
// Do stuff
}
By exposing obj as a property, at least temporarily, with very minimal code changes you can determine what function acquired the lock last and on what thread - just look at the Trace output for the last entry. Of course you can output any other information you might find useful in the getter as well.
No, this will not let you determine when a lock was released, but if it was getting released in a timely fashion, then you didn't actually have a lock contention issue in the first place.
You can implement a Monitor wrapper that saves stack traces & thread names on enter.
Old way:
private object myLock = new object();
...
lock(myLock)
{
DoSomething();
}
...
With code below:
private SmartLock myLock = new SmartLock();
...
myLock.Lock( () =>
{
DoSomething();
}
);
...
Source:
public class SmartLock
{
private object LockObject = new object();
private string HoldingTrace = "";
private static int WARN_TIMEOUT_MS = 5000; //5 secs
public void Lock(Action action)
{
try
{
Enter();
action.Invoke();
}
catch (Exception ex)
{
Globals.Error("SmartLock Lock action", ex);
}
finally
{
Exit();
}
}
private void Enter()
{
try
{
bool locked = false;
int timeoutMS = 0;
while (!locked)
{
//keep trying to get the lock, and warn if not accessible after timeout
locked = Monitor.TryEnter(LockObject, WARN_TIMEOUT_MS);
if (!locked)
{
timeoutMS += WARN_TIMEOUT_MS;
Globals.Warn("Lock held: " + (timeoutMS / 1000) + " secs by " + HoldingTrace + " requested by " + GetStackTrace());
}
}
//save a stack trace for the code that is holding the lock
HoldingTrace = GetStackTrace();
}
catch (Exception ex)
{
Globals.Error("SmartLock Enter", ex);
}
}
private string GetStackTrace()
{
StackTrace trace = new StackTrace();
string threadID = Thread.CurrentThread.Name ?? "";
return "[" + threadID + "]" + trace.ToString().Replace('\n', '|').Replace("\r", "");
}
private void Exit()
{
try
{
Monitor.Exit(LockObject);
HoldingTrace = "";
}
catch (Exception ex)
{
Globals.Error("SmartLock Exit", ex);
}
}
}
Yes, there is a 'Threads' view that you can use in VS. Break anywhere in your application (or click the 'Break All' button) then you can select each thread and view who has the lock (if anyone).
To add it, go to Debug > Windows > Threads (Ctrl+D,T)
Old posts are old.
But i thought i might give a solution i find to be fairly useful for trying to track down dead locks and other locking problems.
I use a disposable class for my lock - I like Monitor but any locking mechanism could be used.
public class MonitorLock : IDisposable
{
public static MonitorLock CreateLock(object value)
{
return new MonitorLock(value);
}
private readonly object _l;
protected MonitorLock(object l)
{
_l = l;
Console.WriteLine("Lock {0} attempt by {1}", _l, Thread.CurrentThread.ManagedThreadId);
Monitor.Enter(_l);
Console.WriteLine("Lock {0} held by {1}" , _l, Thread.CurrentThread.ManagedThreadId);
}
public void Dispose()
{
Monitor.Exit(_l);
Console.WriteLine("Lock {0} released by {1}", _l, Thread.CurrentThread.ManagedThreadId);
}
}
I use a lock object with a name so I can be clear as to which lock I'm trying to aquire.
public class LockObject
{
public string Name { get; set; }
public LockObject(string name)
{
Name = name;
}
public override string ToString()
{
return Name;
}
}
Finally create a lock object, and then in a using block hold the object.
//create an object to lock on
private readonly object _requestLock = new LockObject("_requestLock");
using (MonitorLock.CreateLock(_requestLock))
{
//do some work
}
Output should be something along the lines of
Lock _requestLock attempt by 92
Lock _requestLock held by 92
Lock _requestLock attempt by 19
Lock _requestLock released by 92
Lock _requestLock held by 19
Lock _requestLock released by 19
Hope that someone finds this useful :)
The Managed Stack Explorer from http://mse.codeplex.com/ or http://www.microsoft.com/downloadS/details.aspx?FamilyID=80cf81f7-d710-47e3-8b95-5a6555a230c2&displaylang=en is excellent in such cases.
It hooks into running managed code (appropriate permissions needed) including live code, and grabs a list of running threads. You can double-click on any of them or (more useful in cases like this) select the lot and hit enter for a quick relatively non-invasive (obviously it's going to consume resources, but it goes in and out as quickly as it can) dump of the current stacks of different threads. Great for finding a deadlock, infinite loop, near-infinite loop (for those times when your application accidentally depends upon astronomers being pessimistic about how long the earth will last to have a hope of completing) and other such cases.
I'm not sure in which version this feature was added, but the Visual Studio 2022 debugger now shows in its Call Stack window the ID of the thread that owns the lock on which another thread is waiting to acquire, e.g.,
I found this over here.

Categories