For lucky #13, I want to know what can go terribly wrong with the following code, and why.
class
HardWorker
{
public
void DoMultiThreadedWork(object someParameter)
{
lock (lockObject)
{
// ...
lots of work ...
}
}
private
string lockObject = "lockit";
}
Hint: Think about memory optimizations in the CLR.
Comments
Thanks for the puzzle.
All instances of HardWorker will be locking the same instance of lockObject.
Try this:
string a = "lockit"; // control object
string b = "lockit"; // literal
string c = "LOCKIT".ToLower(); // return from a method
string d = "lock" + "it"; // compile time concatenation
string e1 = "lock";
string e2 = "it";
string e = e1 + e2; // runtime concatenation
Console.WriteLine(object.ReferenceEquals(a, b));
Console.WriteLine(object.ReferenceEquals(a, c));
Console.WriteLine(object.ReferenceEquals(a, d));
Console.WriteLine(object.ReferenceEquals(a, e));
So that assuming instance #1 has the lock then instance #2 wouldn't be able to obtain the lock until instance #1 released it despite the fact that it isn't declared as static.
Using a plain old System.Object instead of a string should sort this out.
See "The lock keyword" in the following documentation: msdn2.microsoft.com/en-us/library/ms173179.aspx
There are other best pratices there, too.
class HardWorker
{
public void DoMultiThreadedWork(object someParameter)
{
lock (lockObject)
{
// ... lots of work ...
}
}
private Int32 lockObject = 123;
}
Sheva
gw: as far as I know, literal string interning is still on by default. Did something change in 2.0? Do you have a link?
"By default when an assembly is loaded, the CLR interns all of the literal strings described in the assembly's metadata. Microsoft learned that this hurts performance significantly due to the additional hash table lookups, so it is now possible to turn this "feature" off...Note that, in an attempt to improve your applications performance, the C# compiler always specifies this attribute/flag whenever you compile an assembly."
Again, I am not saying what above is by any stretch correct, just jogged my memory of what i had read.
String Pooling has all string initialize to the same literal text, refer to a common string. This is done at compile time for a single source file, and as Ken Tong code demostrates, is on by default. (and is also common in non-managed C++ code, and probably in other languages as well). It has the advanced of space, both in run-time ram, and exe size.
String Interning expands on that concept, do assign, at run-time and across multiple assemblies, similar strings to a common string representation. This includes strings which become similar to others via manipulation. It saves run-time memory space,allowing the duplicate representations to be freed & garbage collected, and is therefore largely pointless in a non-managed environment.
However, isn't this optimization only meant to optimize any other literals that share this value?
Since the above example is not a constant wouldn't the literal value be pooled at compile time but a new instance of a string with that literal value be created at runtime? In other words wouldn't the literal value be pooled but each instance of HardWorker would have a unique reference/pointer to a new string of that literal value?