問題我有一個令人沮喪的問題與一些代碼,不知道爲什麼會出現此問題。C#代碼優化導致Interlocked.Exchange()
//
// .NET FRAMEWORK v4.6.2 Console App
static void Main(string[] args)
{
var list = new List<string>{ "aa", "bbb", "cccccc", "dddddddd", "eeeeeeeeeeeeeeee", "fffff", "gg" };
foreach(var item in list)
{
Progress(item);
}
}
private static int _cursorLeft = -1;
private static int _cursorTop = -1;
public static void Progress(string value = null)
{
lock(Console.Out)
{
if(!string.IsNullOrEmpty(value))
{
Console.Write(value);
var left = Console.CursorLeft;
var top = Console.CursorTop;
Interlocked.Exchange(ref _cursorLeft, Console.CursorLeft);
Interlocked.Exchange(ref _cursorTop, Console.CursorTop);
Console.WriteLine();
Console.WriteLine("Left: {0} _ {1}", _cursorLeft, left);
Console.WriteLine("Top: {0} _ {1}", _cursorTop, top);
}
}
}
當沒有那麼結果不出所料代碼優化運行。 _cursorLeft and left只要_cursorTop和頂部是相等的。
aa
Left: 2 _ 2
Top: 0 _ 0
bbb
Left: 3 _ 3
Top: 3 _ 3
但是,當我與代碼優化兩個值_cursorLeft和_cursorTop運行成爲的bizzare:
aa
Left: -65534 _ 2
Top: -65536 _ 0
bb
Left: -65533 _ 3
Top: -65533 _ 3
我發現2個解決方法:
- 設置_cursorLeft和_cursorTop到而不是-1
- 讓Interlocked.Exchange取的值從左 RESP。 頂部
因爲解決方法1不符合我的需求,我結束了與解決方法2:
private static int _cursorLeft = -1;
private static int _cursorTop = -1;
public static void Progress(string value = null)
{
lock(Console.Out)
{
if(!string.IsNullOrEmpty(value))
{
Console.Write(value);
// OLD - does NOT work!
//Interlocked.Exchange(ref _cursorLeft, Console.CursorLeft);
//Interlocked.Exchange(ref _cursorTop, Console.CursorTop);
// NEW - works great!
var left = Console.CursorLeft;
var top = Console.CursorTop;
Interlocked.Exchange(ref _cursorLeft, left); // new
Interlocked.Exchange(ref _cursorTop, top); // new
}
}
}
但是哪裏這個古怪的動作從何而來?
是否有更好的解決方法?
[編輯由Matthew沃森:添加簡化REPRO:]
class Program
{
static void Main()
{
int actual = -1;
Interlocked.Exchange(ref actual, Test.AlwaysReturnsZero);
Console.WriteLine("Actual value: {0}, Expected 0", actual);
}
}
static class Test
{
static short zero;
public static int AlwaysReturnsZero => zero;
}
[編輯由我:]
我想出另一個甚至更短的例如:
class Program
{
private static int _intToExchange = -1;
private static short _innerShort = 2;
// [MethodImpl(MethodImplOptions.NoOptimization)]
static void Main(string[] args)
{
var oldValue = Interlocked.Exchange(ref _intToExchange, _innerShort);
Console.WriteLine("It was: {0}", oldValue);
Console.WriteLine("It is: {0}", _intToExchange);
Console.WriteLine("Expected: {0}", _innerShort);
}
}
除非您不使用優化或將_intToExchange設置爲ushort
範圍內的值,否則您將無法識別該問題。
我可以重現這一點。 –
我冒昧地添加了一個簡化的repro.You可以合併它或刪除它,只要你認爲合適。 –
@MthetheWWats好主意!我真的認爲它必須是一個特定的問題,但它似乎是一個大錯誤。 – Ronin