C++에서 atomics를 사용할 때 포인터의 사용되지 않는 주소 비트에 다른 변수를 팩할 수 있습니다. 필자는 포인터와 함께 플래그, 카운터 등을 원자 적으로 변경할 수 있습니다. C#에서는 그렇게 쉬운 일이 아닙니다. 나는 특별한 것을 의미하는 정적 참조를 사용할 수 있다고 생각하지만, 힙을 압축 할 때 참조를 움직이는 것이 약간 걱정됩니다. 예를 들어,이 샘플 코드에서는 정적 참조 s_cantAddWork를 사용하여 추가하기 위해 닫힌 링크 된 목록을 원자 적으로 표시 할 수 있습니다. 내 질문은, 내가 gc 이동 s_cantAddWork 걱정해야합니까? 고정을 사용해야합니까? 지금까지 이와 같은 코드를 오랫동안 실행 한 후에는 안전하다고 판단됩니다. 그래도 전문가의 말을 듣고 싶습니다.원자 참조 목록에 정적 참조를 "플래그"로 사용할 수 있습니까?
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 뭔가를 이동하면 걱정 할 필요가 없습니다. 귀하의 예제에는 안전하지 않은 코드는 없습니다. –