首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >线程安全BitArray

线程安全BitArray
EN

Code Review用户
提问于 2017-08-07 14:36:58
回答 1查看 588关注 0票数 5

备注:

  • 只支持64位平台。
  • 在负值没有意义的地方使用的ulong
  • 假定库函数是正确的(不管它们是否真的做了我想做的事情,都是另一篇文章的主题)
  • 理想情况下,线程安全的实现将被重构,以便它在另一个类中结束,但是这样可以使我更容易在开发过程中确保正确性。

这是我写线程安全类的第一次真正的冒险。考虑到上面的注释,我是否以一种可能违反我的线程安全声明的方式搞砸了任何事情,或者我正在执行任何没有必要的操作?

代码:

代码语言:javascript
复制
public sealed class BitVector : IEnumerable<bool>
{
    private readonly long[] m_bits;
    private readonly bool m_isThreadSafe;
    private readonly ulong m_length;

    private long m_version = 0L;

    public bool this[long index] {
        get {
            return this[checked((ulong)index)];
        }
        set {
            this[checked((ulong)index)] = value;
        }
    }
    [CLSCompliant(false)]
    public bool this[ulong index] {
        get {
            if (m_length > index) {
                if (m_isThreadSafe) {
                    return BTConcurrent.AtomicRead(ref m_bits[(index / 64UL)]).IsBitSet(checked((int)index.Mod64()));
                }
                else {
                    return m_bits[(index / 64UL)].IsBitSet(checked((int)index.Mod64()));
                }
            }
            else {
                throw new ArgumentOutOfRangeException(paramName: nameof(index));
            }
        }
        set {
            if (m_length > index) {
                if (value) {
                    if (m_isThreadSafe) {
                        unchecked { BTConcurrent.AtomicIncrement(ref m_version); }

                        BTConcurrent.AtomicSetBit(ref m_bits[unchecked(index / 64UL)], checked((int)index.Mod64()));
                    }
                    else {
                        m_bits[unchecked(index / 64UL)].SetBit(checked((int)index.Mod64()));
                    }
                }
                else {
                    if (m_isThreadSafe) {
                        unchecked { BTConcurrent.AtomicIncrement(ref m_version); }

                        BTConcurrent.AtomicClearBit(ref m_bits[unchecked(index / 64UL)], checked((int)index.Mod64()));
                    }
                    else {
                        m_bits[unchecked(index / 64UL)].ClearBit(checked((int)index.Mod64()));
                    }
                }
            }
            else {
                throw new ArgumentOutOfRangeException(paramName: nameof(index));
            }
        }
    }
    public long Length {
        get {
            return checked((long)UnsignedLength);
        }
    }
    [CLSCompliant(false)]
    public ulong UnsignedLength {
        get {
            return m_length;
        }
    }

    [CLSCompliant(false)]
    public BitVector(ulong length, long initBitPattern, bool isThreadSafe) {
        m_bits = new long[((length / 64UL) + Convert.ToUInt64(length.Mod64().IsPositive()))];
        m_isThreadSafe = isThreadSafe;
        m_length = length;

        if (initBitPattern != 0L) {
            SetAll(initBitPattern);
        }
    }
    [CLSCompliant(false)]
    public BitVector(ulong length, bool isThreadSafe) : this(length, 0L, isThreadSafe) { }
    [CLSCompliant(false)]
    public BitVector(ulong length) : this(length, false) { }

    [CLSCompliant(false)]
    public void And(long bitPattern, ulong count) {
        And(this, bitPattern, count);
    }
    public void AndAll(long bitPattern) {
        And(bitPattern, unchecked((ulong)m_bits.LongLength));
    }
    [CLSCompliant(false)]
    public void Clear(ulong count) {
        SetAll(0L, count);
    }
    public void ClearAll() {
        SetAll(0L, unchecked((ulong)m_bits.LongLength));
    }
    public IEnumerator<bool> GetEnumerator() {
        if (m_isThreadSafe) {
            var versionSnapshot = BTConcurrent.AtomicRead(ref m_version);

            for (var i = 0UL; i < UnsignedLength; i++) {
                if (versionSnapshot == BTConcurrent.AtomicRead(ref m_version)) {
                    yield return this[i];
                }
                else {
                    throw new InvalidOperationException(message: "data was mutated during enumeration, unable to continue");
                }
            }
        }
        else {
            for (var i = 0UL; i < UnsignedLength; i++) {
                yield return this[i];
            }
        }
    }
    [CLSCompliant(false)]
    public void Or(long bitPattern, ulong count) {
        Or(this, bitPattern, count);
    }
    public void OrAll(long bitPattern) {
        Or(bitPattern, unchecked((ulong)m_bits.LongLength));
    }
    [CLSCompliant(false)]
    public void Not(long bitPattern, ulong count) {
        Not(this, bitPattern, count);
    }
    public void NotAll(long bitPattern) {
        Not(bitPattern, unchecked((ulong)m_bits.LongLength));
    }
    [CLSCompliant(false)]
    public void SetAll(long bitPattern, ulong count) {
        Set(this, bitPattern, count);
    }
    public void SetAll(long bitPattern) {
        SetAll(bitPattern, ((ulong)m_bits.LongLength));
    }
    public void SetAll() {
        SetAll(-1L);
    }
    public void SetEven() {
        OrAll(6148914691236517205L /* equivalent to 1010....1010 */);
    }
    public void SetOdd() {
        OrAll(-6148914691236517206L /* equivalent to 0101....0101 */);
    }
    [CLSCompliant(false)]
    public void Xor(long bitPattern, ulong count) {
        Xor(this, bitPattern, count);
    }
    public void XorAll(long bitPattern) {
        Xor(bitPattern, ((ulong)m_bits.LongLength));
    }

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
        return GetEnumerator();
    }

    private static void And(BitVector bitVector, long bitPattern, ulong count) {
        if (count > unchecked((ulong)bitVector.m_bits.Length)) {
            throw new ArgumentOutOfRangeException(paramName: nameof(count));
        }

        if (bitVector.m_isThreadSafe) {
            unchecked { BTConcurrent.AtomicIncrement(ref bitVector.m_version); }

            for (var i = 0UL; i < count; i++) {
                BTConcurrent.AtomicAndAssign(ref bitVector.m_bits[i], bitPattern);
            }
        }
        else {
            for (var i = 0UL; i < count; i++) {
                bitVector.m_bits[i] &= bitPattern;
            }
        }
    }
    private static void Not(BitVector bitVector, long bitPattern, ulong count) {
        if (count > unchecked((ulong)bitVector.m_bits.Length)) {
            throw new ArgumentOutOfRangeException(paramName: nameof(count));
        }

        if (bitVector.m_isThreadSafe) {
            unchecked { BTConcurrent.AtomicIncrement(ref bitVector.m_version); }

            for (var i = 0UL; i < count; i++) {
                BTConcurrent.AtomicNotAssign(ref bitVector.m_bits[i]);
            }
        }
        else {
            for (var i = 0UL; i < count; i++) {
                bitVector.m_bits[i] = (~bitPattern);
            }
        }
    }
    private static void Or(BitVector bitVector, long bitPattern, ulong count) {
        if (count > unchecked((ulong)bitVector.m_bits.Length)) {
            throw new ArgumentOutOfRangeException(paramName: nameof(count));
        }

        if (bitVector.m_isThreadSafe) {
            unchecked { BTConcurrent.AtomicIncrement(ref bitVector.m_version); }

            for (var i = 0UL; i < count; i++) {
                BTConcurrent.AtomicOrAssign(ref bitVector.m_bits[i], bitPattern);
            }
        }
        else {
            for (var i = 0UL; i < count; i++) {
                bitVector.m_bits[i] |= bitPattern;
            }
        }
    }
    private static void Set(BitVector bitVector, long bitPattern, ulong count) {
        if (count > unchecked((ulong)bitVector.m_bits.Length)) {
            throw new ArgumentOutOfRangeException(paramName: nameof(count));
        }

        if (bitVector.m_isThreadSafe) {
            unchecked { BTConcurrent.AtomicIncrement(ref bitVector.m_version); }

            for (var i = 0UL; i < count; i++) {
                BTConcurrent.AtomicWrite(ref bitVector.m_bits[i], bitPattern);
            }
        }
        else {
            for (var i = 0UL; i < count; i++) {
                bitVector.m_bits[i] = bitPattern;
            }
        }
    }
    private static void Xor(BitVector bitVector, long bitPattern, ulong count) {
        if (count > unchecked((ulong)bitVector.m_bits.Length)) {
            throw new ArgumentOutOfRangeException(paramName: nameof(count));
        }

        if (bitVector.m_isThreadSafe) {
            unchecked { BTConcurrent.AtomicIncrement(ref bitVector.m_version); }

            for (var i = 0UL; i < count; i++) {
                BTConcurrent.AtomicXorAssign(ref bitVector.m_bits[i], bitPattern);
            }
        }
        else {
            for (var i = 0UL; i < count; i++) {
                bitVector.m_bits[i] ^= bitPattern;
            }
        }
    }
}
EN

回答 1

Code Review用户

发布于 2017-08-08 05:22:59

您不需要在未经检查的上下文中执行像index / 64UL (其中索引是ulong)这样的分区,因为在这种情况下不会发生溢出。另外,您也不需要UL后缀用于64

您确定需要像longulong这样的索引器参数的“大”类型吗?我只会使用intuint,因为它已经足够了。

在CLS兼容的索引器版本中,您应该检查参数是否为负数,并将其转换为ulong,而无需选中上下文:

代码语言:javascript
复制
public bool this[long index]
{
    get
    {
        if (index < 0)
            throw new ArgumentOutOfRangeException(nameof(index), index, "Index is negative.");

        return this[(ulong)index];
    }
    set
    {
        if (index < 0)
            throw new ArgumentOutOfRangeException(nameof(index), index, "Index is negative.");

        this[(ulong)index] = value;
    }
}

将打开的花括号放置在新行上:)

票数 0
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/172302

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档