静态引用可以用作“标志”吗?使用原子链表

本文关键字:链表 标志 引用 静态 | 更新日期: 2023-09-27 18:18:05

在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
            }
        }
    }
}

静态引用可以用作“标志”吗?使用原子链表

安全。

引用不同于地址指针。当c#移动内存时,它将使您的代码透明,除非您使用不安全的操作,如operator的地址。

若要获取一元表达式的地址(计算结果为固定变量),请使用寻址运算符:[MSDN]

 int* p = &number;

如果使用地址,则需要使用unsage关键字将代码标记为不安全。此时,您可能希望使用fixed语句来固定地址。

还有,看一下这个问题的更多细节:

在压缩发生后GC如何更新引用