При использовании атомистики в C++ я могу упаковать другие переменные в неиспользуемые биты адреса указателей. Я могу атомически менять флаги, счетчики и т. Д. Вместе с указателем. В C# это не так просто. Я думаю, что могу использовать статические ссылки, которые означают особые вещи, но я немного обеспокоен тем, что gc перемещает ссылки, когда он уплотняет кучу. Например, в этом примере кода можно атомно пометить связанный список как закрытый для добавления с помощью статической ссылки s_cantAddWork. Мой вопрос в том, нужно ли мне беспокоиться о том, что gc перемещает s_cantAddWork? Нужно ли использовать Fixed? До сих пор, после долгого запуска кода, это кажется безопасным. Я бы хотел услышать это от эксперта.Может ли статическая ссылка использоваться как «флаг» с атомно связанным списком?
using System;
using System.Threading;
namespace Testola {
class Program {
static void Main(string[] args) {
// pile = null
var w = new CWork();
if (!AtomicAddWork(w))
Console.WriteLine("Cant add work!"); // not hit
// pile = 1
w = new CWork();
if (!AtomicAddWork(w))
Console.WriteLine("Cant add work!"); // not hit
// pile = 2,1
w = AtomicGetWork();
// pile = 1
w = new CWork();
if (!AtomicAddWork(w))
Console.WriteLine("Cant add work!"); // not hit
// pile = 3,1
// remove everything from pile and disable adding.
w = AtomicGetAllWorkAndLockOutOtherThreadsFromAddingMoreWork();
// pile = s_cantAddWork
w = new CWork();
if (!AtomicAddWork(w))
Console.WriteLine("Cant add work!"); // HITS THIS!
}
public class CWork {
static int s_cItems = 0;
public static CWork s_cantAddWork = new CWork();
public CWork next;
public string data = (s_cItems++).ToString();
}
static volatile CWork m_workPile;
static bool AtomicAddWork(CWork work) {
while (true) {
var Old = m_workPile;
// WHAT HAPPENS HERE IF GC MOVES s_cantAddWork? <<------------------
// I assume Old is moved too, and all threads are stopped, so my atomic stuff will still work.
if (Old == CWork.s_cantAddWork)
return false;
work.next = Old;
if (Interlocked.CompareExchange(ref m_workPile, work, Old) == Old)
return true; // success
work.next = null;
}
}
static CWork AtomicGetWork() {
while (true) {
var Old = m_workPile;
if (Old == null)
return null;
if (Interlocked.CompareExchange(ref m_workPile, Old.next, Old) == Old)
return Old; // success
}
}
static CWork AtomicGetAllWorkAndLockOutOtherThreadsFromAddingMoreWork() {
while (true) {
var Old = m_workPile;
if (Interlocked.CompareExchange(ref m_workPile, CWork.s_cantAddWork, Old) == Old)
return Old; // success
}
}
}
}
Вам не нужно знать или заботиться, если GC движется что-то, если вы не работаете с небезопасным кодом. В вашем примере нет небезопасного кода. –