.NET ফ্রেমওয়ার্কে সমকালীন হ্যাশসেট <T>?


151

আমি নিম্নলিখিত ক্লাস আছে।

class Test{
    public HashSet<string> Data = new HashSet<string>();
}

আমার বিভিন্ন থ্রেড থেকে "ডেটা" ক্ষেত্রটি পরিবর্তন করতে হবে, তাই আমার বর্তমান থ্রেড-নিরাপদ বাস্তবায়নের বিষয়ে আমি কিছু মতামত চাই।

class Test{
    public HashSet<string> Data = new HashSet<string>();

    public void Add(string Val){
            lock(Data) Data.Add(Val);
    }

    public void Remove(string Val){
            lock(Data) Data.Remove(Val);
    }
}

সরাসরি ফিল্ডে যেতে এবং একাধিক থ্রেড দ্বারা এটি একযোগে অ্যাক্সেস থেকে রক্ষা করার জন্য আরও ভাল সমাধান কি আছে?


কিভাবে অধীনে সংগ্রহের এক ব্যবহার সম্পর্কেSystem.Collections.Concurrent
I4V

8
অবশ্যই, এটি ব্যক্তিগত করুন।
হ্যানস প্যাস্যান্ট

3
একচ্ছত্র দৃষ্টিকোণ থেকে, ডেটা ফিল্ড পাবলিক হওয়ার চেয়ে আপনি অন্যটি যা করেছেন তার সাথে আমি খুব বেশি ভুল দেখতে পাচ্ছি না! যদি এটি উদ্বেগের বিষয় হয় তবে আপনি আরও ভাল পাঠক পারফরম্যান্স রিডার রাইটারলকস্লিম ব্যবহার করে পেতে পারেন। এমএসডিএন.মাইক্রোসফট.এইন- ইউএস
অ্যালান এল্ডার

ReaderWriterLockএকাধিক পাঠক এবং একক লেখক যখন @ অ্যালানেল্ডার সহায়ক (দক্ষ) হবে। ওপি
শ্রীরাম সাক্তিভেল

2
বর্তমান বাস্তবায়ন আসলে 'সমবর্তী' নয় :) এটি কেবল থ্রেড-নিরাপদ।
undefined

উত্তর:


164

আপনার বাস্তবায়ন সঠিক। দুর্ভাগ্যক্রমে .NET ফ্রেমওয়ার্ক একটি অন্তর্নির্মিত সমবর্তী হ্যাশসেট প্রকার সরবরাহ করে না। যাইহোক, কিছু কর্মক্ষেত্র আছে।

সমকালীন অভিধান (প্রস্তাবিত)

এই প্রথমটি হ'ল ConcurrentDictionary<TKey, TValue>নামস্থানে ক্লাসটি ব্যবহার করা System.Collections.Concurrent। ক্ষেত্রে মানটি অর্থহীন, তাই আমরা একটি সাধারণ byte(মেমরিতে 1 বাইট) ব্যবহার করতে পারি ।

private ConcurrentDictionary<string, byte> _data;

এটি প্রস্তাবিত বিকল্প কারণ ধরণটি থ্রেড-সেফ এবং আপনাকে HashSet<T>কী এবং মান ব্যতীত আলাদা আলাদা বস্তু ব্যতীত একই সুবিধা প্রদান করে।

সূত্র: সোস্যাল এমএসডিএন

ConcurrentBag

সদৃশ এন্ট্রিগুলি সম্পর্কে যদি আপনার আপত্তি না থাকে তবে আপনি ConcurrentBag<T>পূর্ববর্তী শ্রেণীর একই নামের জায়গায় ক্লাসটি ব্যবহার করতে পারেন ।

private ConcurrentBag<string> _data;

স্ব-বাস্তবায়ন

অবশেষে, আপনি যেমনটি করেছিলেন, আপনি লক বা অন্যান্য উপায়গুলি ব্যবহার করে আপনার নিজস্ব ডেটা টাইপ প্রয়োগ করতে পারেন। নেট আপনাকে থ্রেড-সেফ হিসাবে সরবরাহ করে। এখানে একটি দুর্দান্ত উদাহরণ: কীভাবে। নেট এ সাম্প্রতিক হ্যাশসেটটি প্রয়োগ করা যায়

এই সমাধানের একমাত্র অপূর্ণতা হ'ল টাইপটি HashSet<T>আনুষ্ঠানিকভাবে একযোগে অ্যাক্সেস করে না, এমনকি পড়া অপারেশনগুলির জন্যও।

আমি লিঙ্কযুক্ত পোস্টের কোডটি উদ্ধৃত করি (মূলত বেন মোশার লিখেছেন )।

using System;
using System.Collections.Generic;
using System.Threading;

namespace BlahBlah.Utilities
{
    public class ConcurrentHashSet<T> : IDisposable
    {
        private readonly ReaderWriterLockSlim _lock = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);
        private readonly HashSet<T> _hashSet = new HashSet<T>();

        #region Implementation of ICollection<T> ...ish
        public bool Add(T item)
        {
            _lock.EnterWriteLock();
            try
            {
                return _hashSet.Add(item);
            }
            finally
            {
                if (_lock.IsWriteLockHeld) _lock.ExitWriteLock();
            }
        }

        public void Clear()
        {
            _lock.EnterWriteLock();
            try
            {
                _hashSet.Clear();
            }
            finally
            {
                if (_lock.IsWriteLockHeld) _lock.ExitWriteLock();
            }
        }

        public bool Contains(T item)
        {
            _lock.EnterReadLock();
            try
            {
                return _hashSet.Contains(item);
            }
            finally
            {
                if (_lock.IsReadLockHeld) _lock.ExitReadLock();
            }
        }

        public bool Remove(T item)
        {
            _lock.EnterWriteLock();
            try
            {
                return _hashSet.Remove(item);
            }
            finally
            {
                if (_lock.IsWriteLockHeld) _lock.ExitWriteLock();
            }
        }

        public int Count
        {
            get
            {
                _lock.EnterReadLock();
                try
                {
                    return _hashSet.Count;
                }
                finally
                {
                    if (_lock.IsReadLockHeld) _lock.ExitReadLock();
                }
            }
        }
        #endregion

        #region Dispose
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
                if (_lock != null)
                    _lock.Dispose();
        }
        ~ConcurrentHashSet()
        {
            Dispose(false);
        }
        #endregion
    }
}

সম্পাদনা: প্রবেশদ্বার লক পদ্ধতিগুলি tryব্লককে ছাড়িয়ে যান , কারণ তারা একটি ব্যতিক্রম ছুঁড়ে ফেলতে পারে এবং finallyব্লকগুলিতে থাকা নির্দেশাবলী কার্যকর করতে পারে ।


8
জাঙ্ক মানগুলির সাথে একটি অভিধান একটি তালিকা
রাল্ফ

44
@ রালফ ওয়েল, এটি একটি সেট নয়, তালিকা নয়, এটি আনর্ডারড থাকার কারণে।
18-18 এ পরিবেশন করুন

11
"সংগ্রহ এবং সিঙ্ক্রোনাইজেশন (থ্রেড সুরক্ষা)" বিষয়ে এমএসডিএন এর পরিবর্তে সংক্ষিপ্ত দলিল অনুসারে , সিস্টেমের মধ্যে ক্লাস সংগ্রহ এবং সম্পর্কিত নেমস্পেসগুলি নিরাপদে একাধিক থ্রেড দ্বারা পড়া যেতে পারে। এর অর্থ হ্যাশসেটটি একাধিক থ্রেড দ্বারা নিরাপদে পড়া যায়।
হ্যাঙ্ক শুল্টজ

7
@ অলিভার, একটি রেফারেন্স এন্ট্রি প্রতি আরও অনেক বেশি মেমরি ব্যবহার করে, যদিও এটি একটি nullরেফারেন্স (রেফারেন্সটি 32-বিট রানটাইমতে 4 বাইট এবং 64-বিট রানটাইমের 8 বাইট প্রয়োজন) needs অতএব, একটি byte, একটি খালি কাঠামো বা অনুরূপ ব্যবহারের ফলে মেমরির পদচিহ্নগুলি হ্রাস পেতে পারে (বা রানটটাইম দ্রুত অ্যাক্সেসের জন্য নেটিভ মেমরির সীমানায় ডেটা প্রান্তিককরণ না করে)।
Lucero

4
স্ব-বাস্তবায়ন কোনও সাম্প্রতিক হ্যাশসেট নয় বরং থ্রেডস্যাফহ্যাশসেট। এই 2 টির মধ্যে একটি বড় পার্থক্য রয়েছে এবং সে কারণেই মাইক্রোসফ্ট সিঙ্ক্রোনাইজড কালেকশনগুলি ত্যাগ করেছে (লোকেরা এটির ভুল হয়েছে)। "কনটেন্ট" হওয়ার জন্য getOrAdd ইত্যাদির মতো ক্রিয়াকলাপগুলি প্রয়োগ করা উচিত (অভিধানের মতো) বা অন্যথায় অতিরিক্ত লকিং ছাড়া সম্মতি নিশ্চিত করা যায় না। তবে আপনার যদি ক্লাসের বাইরে অতিরিক্ত লকিং দরকার হয় তবে আপনি কেন শুরু থেকেই সাধারণ হ্যাশसेट ব্যবহার করবেন না?
জর্জ মাভ্রিতসাকিস

36

একটি মোড়ানো ConcurrentDictionaryবা একটি লক করার পরিবর্তে HashSetআমি একটি বাস্তব ConcurrentHashSetউপর ভিত্তি করে তৈরি ConcurrentDictionary

এই বাস্তবায়ন HashSetআইটেমি'র সেট অপারেশন ছাড়াই আইটেম প্রতি বেসিক অপারেশনগুলিকে সমর্থন করে কারণ তারা সমকালীন পরিস্থিতিতে আইএমওতে কম ধারণা দেয়:

var concurrentHashSet = new ConcurrentHashSet<string>(
    new[]
    {
        "hamster",
        "HAMster",
        "bar",
    },
    StringComparer.OrdinalIgnoreCase);

concurrentHashSet.TryRemove("foo");

if (concurrentHashSet.Contains("BAR"))
{
    Console.WriteLine(concurrentHashSet.Count);
}

আউটপুট: 2

আপনি এটি এখানে নুগেট থেকে পেতে পারেন এবং এখানে গিটহাবের উত্সটি দেখতে পারেন ।


3
এটি গ্রহণযোগ্য উত্তর, দুর্দান্ত বাস্তবায়ন হওয়া উচিত
স্মার্কম্যান

না করা উচিত যোগ নাম পরিবর্তন করে রাখা TryAdd যাতে এটি সঙ্গে সামঞ্জস্যপূর্ণ এর ConcurrentDictionary ?
নিও

8
@ নিও না ... কারণ এটি ইচ্ছাকৃতভাবে হ্যাশসেট <টি> শব্দার্থক ব্যবহার করছে , যেখানে আপনি অ্যাড ডাকবেন এবং এটি একটি বুলিয়ান প্রত্যাবর্তন করবে যা নির্দেশ করে যে আইটেমটি যুক্ত হয়েছে (সত্য), বা এটি ইতিমধ্যে বিদ্যমান (মিথ্যা)। msdn.microsoft.com/en-us/library/bb353005(v=vs.110).aspx
জি-ম্যাক

এটি ISet<T>আসলে ইন্টারফেস বো বাস্তবায়ন করা উচিত HashSet<T>শব্দার্থবিজ্ঞানের সাথে?
নেক্রোম্যান্সার

1
@ নেক্রোমেন্সার যেমনটি উত্তরে বলেছি, আমি মনে করি না যে এই সেটগুলি একসাথে বাস্তবায়নে প্রদান করা অর্থহীন। Overlapsউদাহরণস্বরূপ, হয় পুরো রান জুড়ে উদাহরণটি লক করা দরকার, বা একটি উত্তর সরবরাহ করা হবে যা ইতিমধ্যে ভুল হতে পারে। উভয় বিকল্পগুলি খারাপ আইএমও (এবং গ্রাহকরা বাহ্যিকভাবে যোগ করতে পারেন)।
i3arnon

21

যেহেতু অন্য কারও এটি উল্লেখ করা হয়নি, আমি একটি বিকল্প পদ্ধতির প্রস্তাব দেব যা আপনার নির্দিষ্ট উদ্দেশ্যে উপযুক্ত বা নাও হতে পারে:

মাইক্রোসফ্ট অপরিবর্তনীয় সংগ্রহ

পিছনে এমএস টিমের একটি ব্লগ পোস্ট থেকে :

একই সাথে একইসাথে তৈরি করা এবং চালানো সহজ হলেও, অন্যতম একটি মৌলিক সমস্যা এখনও বিদ্যমান: পারস্পরিক পরিবর্তনীয় ভাগীদার অবস্থা। একাধিক থ্রেড থেকে পড়া সাধারণত খুব সহজ, তবে একবার রাষ্ট্র আপডেট করার প্রয়োজন পরে এটি আরও শক্ত হয়ে যায়, বিশেষত ডিজাইনে যাতে লকিংয়ের প্রয়োজন হয়।

লকিংয়ের বিকল্প হ'ল অপরিবর্তনীয় অবস্থার ব্যবহার করা। অপরিবর্তনীয় ডেটা স্ট্রাকচারগুলি কখনই পরিবর্তিত হবে না তার গ্যারান্টিযুক্ত এবং এভাবে অন্য কারও পায়ের আঙ্গুলের উপর পদক্ষেপ নেওয়ার চিন্তা না করে বিভিন্ন থ্রেডের মধ্যে অবাধে পাস করা যেতে পারে।

এই নকশাটি একটি নতুন সমস্যা তৈরি করেছে যদিও: আপনি প্রতিবার পুরো রাজ্যের অনুলিপি না করে কীভাবে রাজ্যের পরিবর্তনগুলি পরিচালনা করবেন? সংগ্রহগুলি জড়িত থাকার সময় এটি বিশেষত জটিল।

এখানেই অপরিবর্তনীয় সংগ্রহ আসে।

এই সংগ্রহগুলিতে ইমট্যুয়েবল হ্যাশসেট <টি> এবং ইমিউটেবললিস্ট <টি> অন্তর্ভুক্ত রয়েছে

কর্মক্ষমতা

যেহেতু অপরিবর্তনীয় সংগ্রহগুলি কাঠামোগত ভাগ করে নেওয়ার জন্য নীচে গাছের ডেটা স্ট্রাকচার ব্যবহার করে, তাদের কর্মক্ষমতা বৈশিষ্ট্যগুলি পরিবর্তনীয় সংগ্রহ থেকে পৃথক from লকিং পরিবর্তনশীল সংগ্রহের সাথে তুলনা করার সময়, ফলাফলগুলি লক যুক্তি এবং অ্যাক্সেসের ধরণগুলির উপর নির্ভর করবে। তবে অপরিবর্তনীয় সংগ্রহ সম্পর্কে অন্য একটি ব্লগ পোস্ট থেকে নেওয়া :

প্রশ্ন: আমি শুনেছি যে অপরিবর্তনীয় সংগ্রহগুলি ধীর। এগুলি কি অন্যরকম? কর্মক্ষমতা বা স্মৃতিশক্তি যখন গুরুত্বপূর্ণ তখন আমি সেগুলি ব্যবহার করতে পারি?

উত্তর: এই অপরিবর্তনীয় সংগ্রহগুলি মেমরি ভাগ করে নেওয়ার ক্ষেত্রে ভারসাম্য বজায় রেখে পরিবর্তনীয় সংগ্রহগুলিতে প্রতিযোগিতামূলক পারফরম্যান্স বৈশিষ্ট্যগুলির জন্য অত্যন্ত সুরযুক্ত হয়েছে। কিছু ক্ষেত্রে এগুলি উভয়ই অ্যালগরিদম এবং বাস্তব সময়ে পারস্পরিক পরিবর্তনগুলির সংগ্রহের তুলনায় প্রায় দ্রুত হয়, কখনও কখনও এমনকি দ্রুতও হয়, অন্য ক্ষেত্রে সেগুলি অ্যালগোরিদমিকভাবে আরও জটিল। অনেক ক্ষেত্রে তবে পার্থক্য নগণ্য হবে। কাজটি সম্পন্ন করার জন্য আপনার সাধারণতম কোডটি ব্যবহার করা উচিত এবং তারপরে প্রয়োজনীয় পারফরম্যান্সের জন্য টিউন করুন। অপরিবর্তনীয় সংগ্রহগুলি আপনাকে সহজ কোড লিখতে সহায়তা করে, বিশেষত যখন থ্রেড-সুরক্ষা বিবেচনা করতে হয়।

অন্য কথায়, অনেক ক্ষেত্রে পার্থক্যটি লক্ষণীয় হবে না এবং আপনার সহজ বিকল্পের সাথে চলতে হবে - যা সমবর্তী সেটগুলির জন্য ব্যবহার করা হবে ImmutableHashSet<T>, যেহেতু আপনার কোনও বিদ্যমান লকিং মিউটেবল বাস্তবায়ন নেই! :-)


1
ImmutableHashSet<T>আপনার অভিপ্রায়টি যদি একাধিক থ্রেড থেকে ভাগ করা রাষ্ট্র আপডেট করা হয় তবে আমি এখানে কিছু মিস করছি?
tugberk

7
@ টগবার্ক হ্যাঁ এবং না। যেহেতু সেটটি পরিবর্তনযোগ্য নয়, আপনাকে এটির রেফারেন্স আপডেট করতে হবে, যা সংগ্রহ নিজেই আপনাকে সহায়তা করে না। সুসংবাদটি হ'ল আপনি শেয়ার্ড ডেটা স্ট্রাকচার আপডেট করার জটিল সমস্যাটি একাধিক থ্রেড থেকে ভাগ করে নেওয়া রেফারেন্স আপডেট করার খুব সহজ সমস্যাটিতে হ্রাস করেছেন। লাইব্রেরিটি আপনাকে ImmutableInterlocked.Update পদ্ধতি আপনাকে সহায়তা করার জন্য সরবরাহ করে।
সেরেন বোইসেন

1
@ সেরেনবয়েসেনড অপরিবর্তনীয় সংগ্রহগুলি সম্পর্কে পড়ুন এবং সেগুলি কীভাবে নিরাপদে থ্রেড ব্যবহার করবেন তা নির্ধারণের চেষ্টা করেছিলেন। ImmutableInterlocked.Updateঅনুপস্থিত লিঙ্ক বলে মনে হচ্ছে। ধন্যবাদ!
xneg

4

ISet<T>একযোগে তৈরি করার বিষয়ে জটিল অংশটি হ'ল সেট পদ্ধতিগুলি (ইউনিয়ন, ছেদটি, পার্থক্য) প্রকৃতির পুনরাবৃত্ত হয়। খুব কমপক্ষে আপনাকে উভয় সেট লক করার সময় অপারেশনের সাথে জড়িত সেটের একটিতে সমস্ত এন সদস্যের সাথে পুনরাবৃত্তি করতে হবে।

ConcurrentDictionary<T,byte>যখন আপনাকে পুনরাবৃত্তির সময় পুরো সেটটি লক করতে হয় আপনি তার সুবিধাগুলি হারাবেন । লক না করে এই ক্রিয়াকলাপগুলি থ্রেড নিরাপদ নয়।

অতিরিক্ত সংযুক্ত ওভারহেড দেওয়া ConcurrentDictionary<T,byte>, সম্ভবত হালকা ওজন ব্যবহার করা HashSet<T>এবং তালার মধ্যে সমস্ত কিছু ঘিরে রাখা সম্ভবত বুদ্ধিমানের ।

আপনার যদি সেট অপারেশনগুলির প্রয়োজন না হয়, আপনি কী যুক্ত করার সময় মান হিসাবে ব্যবহার করুন ConcurrentDictionary<T,byte>এবং ব্যবহার করুন default(byte)


2

আমি সম্পূর্ণ সমাধানগুলি পছন্দ করি তাই আমি এটি করেছি: আমার মাইন্ডটি আলাদা ফ্যাশনে প্রয়োগ করা হবে কারণ আমি দেখতে পাচ্ছি না কেন তার মানগুলি গণনা করার চেষ্টা করার সময় কেন হ্যাশসেটটি পড়তে নিষেধ করা উচিত।

@ জেন, এটি শুরু করার জন্য ধন্যবাদ

[DebuggerDisplay("Count = {Count}")]
[Serializable]
public class ConcurrentHashSet<T> : ICollection<T>, ISet<T>, ISerializable, IDeserializationCallback
{
    private readonly ReaderWriterLockSlim _lock = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);

    private readonly HashSet<T> _hashSet = new HashSet<T>();

    public ConcurrentHashSet()
    {
    }

    public ConcurrentHashSet(IEqualityComparer<T> comparer)
    {
        _hashSet = new HashSet<T>(comparer);
    }

    public ConcurrentHashSet(IEnumerable<T> collection)
    {
        _hashSet = new HashSet<T>(collection);
    }

    public ConcurrentHashSet(IEnumerable<T> collection, IEqualityComparer<T> comparer)
    {
        _hashSet = new HashSet<T>(collection, comparer);
    }

    protected ConcurrentHashSet(SerializationInfo info, StreamingContext context)
    {
        _hashSet = new HashSet<T>();

        // not sure about this one really...
        var iSerializable = _hashSet as ISerializable;
        iSerializable.GetObjectData(info, context);
    }

    #region Dispose

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (disposing)
            if (_lock != null)
                _lock.Dispose();
    }

    public IEnumerator<T> GetEnumerator()
    {
        return _hashSet.GetEnumerator();
    }

    ~ConcurrentHashSet()
    {
        Dispose(false);
    }

    public void OnDeserialization(object sender)
    {
        _hashSet.OnDeserialization(sender);
    }

    public void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        _hashSet.GetObjectData(info, context);
    }

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

    #endregion

    public void Add(T item)
    {
        _lock.EnterWriteLock();
        try
        {
            _hashSet.Add(item);
        }
        finally
        {
            if(_lock.IsWriteLockHeld) _lock.ExitWriteLock();
        }
    }

    public void UnionWith(IEnumerable<T> other)
    {
        _lock.EnterWriteLock();
        _lock.EnterReadLock();
        try
        {
            _hashSet.UnionWith(other);
        }
        finally
        {
            if (_lock.IsWriteLockHeld) _lock.ExitWriteLock();
            if (_lock.IsReadLockHeld) _lock.ExitReadLock();
        }
    }

    public void IntersectWith(IEnumerable<T> other)
    {
        _lock.EnterWriteLock();
        _lock.EnterReadLock();
        try
        {
            _hashSet.IntersectWith(other);
        }
        finally
        {
            if (_lock.IsWriteLockHeld) _lock.ExitWriteLock();
            if (_lock.IsReadLockHeld) _lock.ExitReadLock();
        }
    }

    public void ExceptWith(IEnumerable<T> other)
    {
        _lock.EnterWriteLock();
        _lock.EnterReadLock();
        try
        {
            _hashSet.ExceptWith(other);
        }
        finally
        {
            if (_lock.IsWriteLockHeld) _lock.ExitWriteLock();
            if (_lock.IsReadLockHeld) _lock.ExitReadLock();
        }
    }

    public void SymmetricExceptWith(IEnumerable<T> other)
    {
        _lock.EnterWriteLock();
        try
        {
            _hashSet.SymmetricExceptWith(other);
        }
        finally
        {
            if (_lock.IsWriteLockHeld) _lock.ExitWriteLock();
        }
    }

    public bool IsSubsetOf(IEnumerable<T> other)
    {
        _lock.EnterWriteLock();
        try
        {
            return _hashSet.IsSubsetOf(other);
        }
        finally
        {
            if (_lock.IsWriteLockHeld) _lock.ExitWriteLock();
        }
    }

    public bool IsSupersetOf(IEnumerable<T> other)
    {
        _lock.EnterWriteLock();
        try
        {
            return _hashSet.IsSupersetOf(other);
        }
        finally
        {
            if (_lock.IsWriteLockHeld) _lock.ExitWriteLock();
        }
    }

    public bool IsProperSupersetOf(IEnumerable<T> other)
    {
        _lock.EnterWriteLock();
        try
        {
            return _hashSet.IsProperSupersetOf(other);
        }
        finally
        {
            if (_lock.IsWriteLockHeld) _lock.ExitWriteLock();
        }
    }

    public bool IsProperSubsetOf(IEnumerable<T> other)
    {
        _lock.EnterWriteLock();
        try
        {
            return _hashSet.IsProperSubsetOf(other);
        }
        finally
        {
            if (_lock.IsWriteLockHeld) _lock.ExitWriteLock();
        }
    }

    public bool Overlaps(IEnumerable<T> other)
    {
        _lock.EnterWriteLock();
        try
        {
            return _hashSet.Overlaps(other);
        }
        finally
        {
            if (_lock.IsWriteLockHeld) _lock.ExitWriteLock();
        }
    }

    public bool SetEquals(IEnumerable<T> other)
    {
        _lock.EnterWriteLock();
        try
        {
            return _hashSet.SetEquals(other);
        }
        finally
        {
            if (_lock.IsWriteLockHeld) _lock.ExitWriteLock();
        }
    }

    bool ISet<T>.Add(T item)
    {
        _lock.EnterWriteLock();
        try
        {
            return _hashSet.Add(item);
        }
        finally
        {
            if (_lock.IsWriteLockHeld) _lock.ExitWriteLock();
        }
    }

    public void Clear()
    {
        _lock.EnterWriteLock();
        try
        {
            _hashSet.Clear();
        }
        finally
        {
            if (_lock.IsWriteLockHeld) _lock.ExitWriteLock();
        }
    }

    public bool Contains(T item)
    {
        _lock.EnterWriteLock();
        try
        {
            return _hashSet.Contains(item);
        }
        finally
        {
            if (_lock.IsWriteLockHeld) _lock.ExitWriteLock();
        }
    }

    public void CopyTo(T[] array, int arrayIndex)
    {
        _lock.EnterWriteLock();
        try
        {
            _hashSet.CopyTo(array, arrayIndex);
        }
        finally
        {
            if (_lock.IsWriteLockHeld) _lock.ExitWriteLock();
        }
    }

    public bool Remove(T item)
    {
        _lock.EnterWriteLock();
        try
        {
            return _hashSet.Remove(item);
        }
        finally
        {
            if (_lock.IsWriteLockHeld) _lock.ExitWriteLock();
        }
    }

    public int Count
    {
        get
        {
            _lock.EnterWriteLock();
            try
            {
                return _hashSet.Count;
            }
            finally
            {
                if(_lock.IsWriteLockHeld) _lock.ExitWriteLock();
            }

        }
    }

    public bool IsReadOnly
    {
        get { return false; }
    }
}

লকটি নিষ্পত্তি হয়ে যায় ... তবে অভ্যন্তরীণ হ্যাশসেটের কী হবে, এর স্মৃতি কখন প্রকাশিত হয়?
ডেভিড রেটেনব্যাকার

1
@ ওয়ারप्पा এটি আবর্জনা সংগ্রহের পরে মুক্তি পেয়েছে। আমি ক্লাসের মধ্যে ম্যানুয়ালি জিনিসগুলিকে নালাগ্রস্থ করে এবং তাদের সম্পূর্ণ উপস্থিতি পরিষ্কার করার সময় কেবল যখন বিষয়গুলিতে ইভেন্ট থাকে এবং এইভাবে মেমরি ফাঁস হতে পারে (আপনি যখন পর্যবেক্ষণযোগ্য সংগ্রহ এবং এর পরিবর্তিত ইভেন্ট ব্যবহার করবেন)) আপনি যদি বিষয় সম্পর্কে আমার উপলব্ধিতে জ্ঞান যোগ করতে পারেন তবে আমি পরামর্শের জন্য উন্মুক্ত। আমি আবর্জনা সংগ্রহের বিষয়ে গবেষণা করতে বেশ কয়েকদিন ব্যয় করেছি এবং নতুন তথ্য সম্পর্কে সর্বদা আগ্রহী
Dbl

@ AndreasMüller ভাল উত্তর, তবে আমি ভাবছি আপনি '_ লক.ইনটারওয়াইটলক ();' এর পরে '_লক.এন্টার্টার রিডলক ();' 'ইন্টারসেকট উইথ' এর মতো কিছু পদ্ধতিতে আমি মনে করি যে এখানে পড়ার চেহারাটির কোনও প্রয়োজন নেই কারণ লেখার লকটি কোনও ডিফল্টরূপে প্রবেশের সময় কোনও পাঠ (গুলি) আটকাতে পারে।
জালাল বলেছেন

আপনি যদি সর্বদা অবশ্যই থাকেন তবে EnterWriteLockকেন EnterReadLockউপস্থিত রয়েছে? এটি কি পঠিত লকটি যেমন ব্যবহারের জন্য ব্যবহার করা যায় না Contains?
এরিক

2
এটি কনক্র্যান্টহ্যাশসেট নয় বরং থ্রেডস্যাফহ্যাশসেট। স্ব-বাস্তবায়ন সম্পর্কিত @ জেনলুলজের উত্তরটিতে আমার মন্তব্য দেখুন। আমি 99% নিশ্চিত যে এই বাস্তবায়নগুলি যে কেউ ব্যবহার করেছে তাদের প্রয়োগতে মারাত্মক ত্রুটি রয়েছে।
জর্জ মাভ্রিতসাকিস
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.