Andrew Rondeau

Software Developer, Audio Enthusiast

Software Development

Topics where I discuss software development

Object Equality in C#

- Posted in Software Development by

In the above-linked answer on Stack Overflow, I explained the different kinds of equivalence in programming, and how they are implemented in C#.

To summarize, in programming, there are four kinds of object equivalence:

  1. Reference Equality, object.ReferenceEquals(a, b): The two variables point to the same exact object in RAM. (If this were C, both variables would have the same exact pointer.)
  2. Interchangeability, a == b: The two variables refer to objects that are completely interchangeable. Thus, when a == b, Func(a,b) and Func(b,a) do the same thing.
  3. Semantic Equality, object.Equals(a, b): At this exact moment in time, the two objects mean the same thing.
  4. Entity equality, a.Id == b.Id: The two objects refer to the same entity, such as a database row, but don’t have to have the same contents.

This blog entry is a response to a question I got in a stack overflow post: How to get non-current thread's stacktrace? [In C# / .Net] Specifically, I was asked if there were alternatives to the originally-obsolete solution: https://stackoverflow.com/questions/285031/how-to-get-non-current-threads-stacktrace/9595704?noredirect=1#comment125211968_9595704.

The author of the solution, who also writes the renowned LINQPad, recently revised his answer. I'd use care with following Joe's suggestion in shipping code, because what works correctly in a tool like LINQPad may not be appropriate for the environment that your application runs in. Specifically, Joe's suggestion may not work in the various sandboxes, non-admin, ect, environments that .Net applications frequently run in.

A bit about my background. For almost a decade I was the desktop client lead for Syncplicity, a file synchronization product similar to Dropbox, OneDrive, and Google drive. While I led the desktop client, we were the most performant and scalable product on the marketplace. The desktop client was a highly multi-threaded C# desktop application. I have quite a lot of experience developing and debugging multithreaded .Net applications.

I'm assuming the person who asked me for alternatives to getting another thread’s stack trace wants to log collect debugging information; or otherwise needs to fix some threading issues.

Is the Stack Trace for Logging?

I wish in .Net that it was very easy to get another thread's stack trace, because then it would be significantly easier to diagnose certain kinds of bugs like deadlocks and other situations where a thread is blocked. Then it would be easier to include defensive “bug detector” code to log what a thread is doing if it holds a lock for too long! Depending on your application's environment, you can't always create a process to obtain a stack trace.

Unfortunately, the quick answer to “are there alternatives”, is that a multithreaded application needs a good logging strategy. The logger should always include the thread name, and thread ID. If you use async code, include Task.CurrentTaskId. Multi-server applications will also need to include the process ID, and the server instance number. Log4net can be configured to include these. Do not configure the logger to include stack traces, except in controlled debugging environments, because logging stack traces in every logging statement incurs extreme CPU overhead and performance will suffer.

When examining logs, filter based on the thread ID, or Task.CurrentTaskId for async code. (And filter on machine ID and process ID for distributed code). This will provide a sequential list of each logging event from the thread. It may be necessary to add logging statements in troublesome areas of code to give yourself hints about what to search for in your logs.

It may be occasionally useful to include a stack trace (Environment.StackTrace) in carefully selected logging statements. Consider restricting logging stack traces to either debug builds or via some kind of a configuration setting. (Remember, logging a stack trace incurs a high performance penalty.)

Important: Any kind of logging, especially stack trace logging, will change timing of race conditions and deadlocks. Assuming that your bug is some kind of a threading issue, the logging you add could trigger a “Fermi's paradox” situation where you either reproduce the bug more, or less frequently, based on how you log!

If you are directly creating threads, it's very useful to name your threads, and include the thread name in your logs. This makes it very easy to track down the specific thread in your log.

If you are able to reproduce your problem when running your code inside of the Visual Studio debugger, when you break into the debugger, you can see a list of all your threads (and tasks). This also allows you to see each thread's stack trace! (Yay!) Assuming that you're logging the thread ID (and/or task Id), it should be very easy to find the specific thread that you are trying to debug.

Some Other Helpful multithreaded Techniques

If you are having problems with deadlocks or general threading issues, here are some additional strategies:

  • If you have a critical method that has a lot of callers, and could block for too long, add a string argument to the method. Give each call to the method a unique name. In your method, set a timer to log the string if the call takes longer than what you consider reasonable.
  • Encapsulate your shared state so that it is prohibitively difficult to access it outside of a lock. For example, your shared state could be encapsulated in an object that is only accessible through a lambda. Then the object should have protections that prevent calling it from a different thread or holding on to the object outside of the lambda.
  • Take the time to learn about programming with immutable values. If you have shared state, but the object itself is immutable, then it's safe to read from any thread without a lock. (Your code still needs to handle stale state.)
  • If you are having problems with deadlocks, consider replacing the lock keyword with a pattern that includes timeouts. These exceptions can help you diagnose deadlocks, or at a minimum, allow you to gracefully recover from such a situation. For example: https://github.com/GWBasic/ObjectCloud/blob/master/Server/ObjectCloud.Common/Threading/TimedLock.cs

Don’t Make Novice Mistakes

Now if you are trying to get a thread stack trace because you need to communicate among threads or wait for a thread to get into a particular state…Well… That's a novice mistake! (And depending on what you're doing, it might be time to admit you've gotten over your head!) Locking, monitors, wait handles, task completion sources, queues, fibers, mutexes, semaphores, critical sections, and other ways of coordination among threads are advanced programming techniques. Although I encourage you to learn, I really do recommend that you have a couple of years experience under your belt, or be in a more advanced computer science class, before you do multi-threaded programming in a professional setting.

Ok, but, really, is there a way to get another thread’s stack trace? (Without creating another process)

But if you really need to get another thread's stack trace at runtime when you don't have a debugger available, this is prohibitively difficult. I will try to explain why to the best of my ability.

I'm going to assume that you know a decent amount of multi-threaded programming, and that sharing state, specifically data structures, among running threads is very difficult. One thread just can’t safely read another thread’s data structures unless they are designed to be thread-safe; or locking is used. Often, allowing one thread to read another thread’s state incurs a performance penalty. An experienced software engineer can weigh the performance trade-offs of different approaches, such as locking versus lock free data structures. It's my professional opinion that designing .Net’s stack so that a stack trace can be read in a non-blocking manner will cause a prohibitive performance degradation to the entire .Net framework.

This is why a thread needs to be suspended in order to get its stack trace from another thread. Why calling something like Thread.Suspend is problematic is more difficult for me to explain, because I have never worked with the internals of .net and the operating system. This response probably explains it best: https://stackoverflow.com/a/3602878/1711103.

I do suspect that a very talented programmer could figure out how to modify .Net to allow getting other threads' stack traces at runtime without relying on an additional process. (After all, the garbage collector does walk the stack!) It would be very interesting to hear from one of Microsoft’s developers to know if this is feasible, and what kind of tradeoffs this would incur.

Conclusion

So there you have it: Use a logging strategy that includes information about each thread. Try to reproduce the bug inside a debugger, because the debugger will give you the stack trace of all threads. Make sure you have the experience to implement multi-threaded programming correctly. (Or be willing to admit that you've gotten over your head.) Given that .Net’s garbage collector walks threads’ stacks, I do wish that .Net allowed getting another thread’s stack trace for diagnostic purposes.

The web is full of various discussions on how to embed C# into JavaScript. Most of these approaches are flawed because they rely on the deprecated Microsoft.JScript APIs. Other approaches, like hosting JavaScript in a WebBrowser control, aren't portable. In my particular situation, I need an embedded JavaScript engine that will work on Windows, Mac, and Linux. It has to work equally well in the .NET and Mono runtimes, and ideally, shouldn't require recompiling for each Operating System. I ended up using the IKVM tool to convert Rhino, a JavaScript interpreter written in Java, into a CLR DLL.

Download: PDF Thumbnail Generator - OSX.zip

From Readme.txt

PDF Thumbnail Generator for OSX
(Developed and tested on Leopard)

Version 1.0
March 15, 2009

Andrew Rondeau
http://andrewrondeau.com

All contents of this zip file are freely copyable.  For more information,
please contact me at http://andrewrondeau.com

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

About:

The PDF Thumbnail Generator is designed to allow for easy creation of
thumbnails from PDF files.

There are two versions:

 - Create Thumbnails of the First Page of Many PDFs:
     Creates a thumbnail of the first page of every PDF that is selected
     when the workflow is run

 - Create Thumbnails of Every Page of a Single PDF:
     Creates a thumbnail of every page of a PDF, allows for interactive
     saving of desired pages.

To run, select the Workflow application with the robot icon.  The document
icon will open the source in Automator if you choose to edit the
workflow.


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

Create Thumbnails of the First Page of Many PDFs:

When run, you will be able to select multiple PDF files.  You will then be
prompted for some options; such as image size and file type.  The thumbnails
will be saved in the same folder as the source PDF files, with the name
"Copy of xxx.jpeg"

The thumbnails will always be the first page of each PDF file.

This workflow might also work with other kinds of files, although it was
only tested with PDFs.  I will only support this script with PDF files.


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

Create Thumbnails of Every Page of a Single PDF

Sometimes, the thumbnails automatically generated from the first page of a
PDF file aren't what's needed.  In some instances, the best page for a
thumbnail isn't the first page.  Other times, the page needs rotation before
being saved as a thumbnail.

This workflow is designed for when more care must be taken with generating
a thumbnail.

When the workflow is run, you will be able to select a single PDF file.
You will then be prompted for many options, such as image type, size, and
compression quality.

Some steps might take a few seconds.  If you have a large PDF, you might
have to wait a minute or two.

Once resizing is complete, the PDF will open in four different Preview
windows.  Each window will have a different rotation of the PDF, either 0,
90, 180, or 270 degrees.  The pages will be out-of-order.  In Preview, you
will need to select the page(s) that you want to save, and then navigate
to File -> Save As.

I wanted to experiment with using .NET's TypeBuilder class to automatically generate classes at runtime. For my experiment, I decided to implement a function, that, given an interface, returns a fully functional object that implements the interface. The programmer does not have to create a class to implement the interface.

In this article, I will first describe how one uses the automatic interface implementer. Later, I will describe how I used reflection and .NET's TypeBuilder to, at runtime, dynamically create Types that implement interfaces.

The below letter was written in response to a statement from Howard Schmidt, former White House cybersecurity advisor. He argued that software developers are solely responsible for security issues. My response, states that the company developing software needs to be held liable for defects.


As a professional software engineer, I strongly disagree with the stance that “Software developers should be held personally accountable for the security of the code they write”. My opinion is based on an engineering disaster that I studied when I was in college.

In 1986, the spaceship Challenger exploded, killing the astronauts that it carried. Upon investigation, it was found that the engineers who designed the faulty parts discovered the problem and notified management. The real fault for the Challenger disaster was miscommunication and an unwillingness to miss a launch date.

Negligent Software Developers are not the only cause of security holes. Inadequate testing, complicated development tools, lack of “proofreading” source code, poor user interfaces, and bad management also need to share the blame. For example, it is common in the software industry for management to set unrealistic development timelines, resulting in software is written quickly and shoddily.

With automobiles and baby strollers, the entire company is held liable for defects, not the engineers. Likewise, it is appropriate to hold software companies, not software developers, liable for security holes.