থ্রেড-নিরাপদ তালিকা <টি> সম্পত্তি


121

আমি List<T>একটি সম্পত্তি হিসাবে একটি বাস্তবায়ন চাই যা কোনও সন্দেহ ছাড়াই নিরাপদে থ্রেড ব্যবহার করা যায় used

এটার মতো কিছু:

private List<T> _list;

private List<T> MyT
{
    get { // return a copy of _list; }
    set { _list = value; }
}

এখনও মনে হচ্ছে আমাকে সংগ্রহের একটি অনুলিপি (ক্লোন করা) ফিরিয়ে দেওয়া দরকার তাই যদি কোথাও আমরা সংগ্রহটি পুনরাবৃত্তি করি এবং একই সময়ে সংগ্রহটি সেট করা থাকে, তবে কোনও ব্যতিক্রম উত্থাপিত হবে না।

কোনও থ্রেড-নিরাপদ সংগ্রহের সম্পত্তি কীভাবে বাস্তবায়ন করবেন?


4
লক ব্যবহার করুন, এটি করা উচিত।
atoMerz

IList<T>(বনাম List<T>) এর থ্রেড-নিরাপদ প্রয়োগ ব্যবহার করতে পারবেন ?
গ্রেগ


ব্লকিংকলেশন বা সমকালীন অভিধান ব্যবহার করুন
কুমার চন্দ্রকেতু

সম্পত্তির পিছনে কী কী অপারেশন আপনার করা দরকার? এটা কি সম্ভব যে List<T>প্রয়োগকারী সমস্ত কিছুর দরকার নেই ? যদি হ্যাঁ, তবে আপনি কি দয়া করে এমন একটি ইন্টারফেস সরবরাহ করতে পারেন যা আপনার List<T>ইতিমধ্যে যা আছে তা সম্পর্কে জিজ্ঞাসা করার পরিবর্তে প্রয়োজন ?
ভিক্টর ইয়ারেমা

উত্তর:


185

আপনি নেট 4 targetting হয় সেখানে কয়েকটি বিকল্প রইল System.Collections.Concurrent নামস্থান

আপনি ConcurrentBag<T>এই ক্ষেত্রে পরিবর্তে ব্যবহার করতে পারেনList<T>


5
তালিকার মতো <T> এবং অভিধানের বিপরীতে, সমকালীন ব্যাগ সদৃশগুলি গ্রহণ করে।
হালকা

114
ConcurrentBagআনর্ডারড কালেকশন, সুতরাং List<T>এটির আদেশের গ্যারান্টি নেই unlike এছাড়াও আপনি সূচী দ্বারা আইটেম অ্যাক্সেস করতে পারবেন না।
রাদেক স্ট্রোমস্কý

11
@ রাদেকস্ট্রোমস্কে ঠিক আছে, এবং আপনি যদি অর্ডার করা সমবর্তী তালিকাগুলি চান তবে আপনি কনকন্ট্রিউ কিউ (ফিফো) বা কনকন্টারস্ট্যাক (এলআইএফও) চেষ্টা করতে পারেন ।
Caio Cunha


12
সমকালীন
ব্যাগ আইলিস্ট

86

এমনকি সর্বাধিক ভোট পেয়েও কেউ সাধারণত System.Collections.Concurrent.ConcurrentBag<T>থ্রেড-সেফ রিপ্লেসমেন্ট হিসাবে গ্রহণ করতে পারে না System.Collections.Generic.List<T>কারণ এটি (রাদেক স্ট্রোমস্কে ইতিমধ্যে এটি নির্দেশ করেছেন) অর্ডার করা হয়নি।

তবে একটি ক্লাস বলা হয়ে থাকে System.Collections.Generic.SynchronizedCollection<T>যা ইতিমধ্যে ফ্রেমওয়ার্কের নেট নেট part.০ অংশের পরে থেকেই রয়েছে তবে এটি এমন জায়গায় খুব ভালভাবে লুকানো আছে যেখানে কেউ এটি আশা করে না যে এটি খুব কম জানা আছে এবং সম্ভবত আপনি কখনই এটিকে হোঁচট খেতে পারেননি (কমপক্ষে আমি কখনো করিনি).

SynchronizedCollection<T>অ্যাসেম্বলি সিস্টেম.সেসওয়ারমোডেল.ডিএল (যা ক্লায়েন্ট প্রোফাইলের অংশ তবে পোর্টেবল ক্লাস লাইব্রেরির অংশ নয়) তে সংকলিত হয়েছে ।

আশা করি এইটি কাজ করবে.


3
আমি ক্রন্দন করি যে এটি মূল স্বচ্ছন্দে নয়: simple একটি সাধারণ সিঙ্ক্রোনাইজড সংগ্রহ প্রায়শই যা প্রয়োজন তা হয়।
ব্যবহারকারী 2864740

এই বিকল্পটির অতিরিক্ত সহায়ক আলোচনা: স্ট্যাকওভারফ্লো.com
জন স্নাইডার

2
এটি ভালভাবে লুকানো রয়েছে কারণ সিস্টেম.কলেকশনস.কন্ট্রন্টের ক্লাসের পক্ষে হ্রাস করা হয়েছে।
denfromufa

3
এবং নেট
কোরটিতে

2
@ এডেনফ্রোমুফায় এটি দেখতে পছন্দ করে তারা এটিকে নেট নেট ২.০ ডক্স.মাইক্রোসফ্ট্র
engg/

17

আমার মনে হয় থ্রেডস্যাফলিস্ট ক্লাসের একটি নমুনা তৈরি করা সহজ হবে:

public class ThreadSafeList<T> : IList<T>
{
    protected List<T> _interalList = new List<T>();

    // Other Elements of IList implementation

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

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

    protected static object _lock = new object();

    public List<T> Clone()
    {
        List<T> newList = new List<T>();

        lock (_lock)
        {
            _interalList.ForEach(x => newList.Add(x));
        }

        return newList;
    }
}

আপনি একজন গণকের অনুরোধ করার আগে কেবল তালিকাটি ক্লোন করে রেখেছেন এবং এইভাবে কোনও গণনা এমন একটি অনুলিপি চালু করছে যা চলমান অবস্থায় সংশোধন করা যায় না।


1
এটি কি অগভীর ক্লোন নয়? যদি Tএকটি রেফারেন্স টাইপ হয়, এটি কি কেবলমাত্র সমস্ত আসল অবজেক্টের রেফারেন্স যুক্ত একটি নতুন তালিকা ফেরত দেবে না? যদি এটি হয় তবে এই পদ্ধতির ফলে থ্রেডিংয়ের সমস্যা হতে পারে, কারণ তালিকার বিভিন্ন "অনুলিপি" এর মাধ্যমে একাধিক থ্রেডের মাধ্যমে তালিকা অবজেক্টগুলি অ্যাক্সেস করা যেতে পারে।
জোয়েল বি

3
সঠিক, এটি একটি অগভীর অনুলিপি। মূল বক্তব্যটি হ'ল একটি ক্লোন করা সেট ছিল যা পুনরাবৃত্তি করা নিরাপদ হবে (সুতরাং newListকোনও আইটেম যুক্ত বা অপসারণ করা হবে না যা গুণকে অকার্যকর করবে)।
তেজস

7
_লক স্থির হওয়া উচিত?
মাইক ওয়ার্ড

4
আর একটি চিন্তা। এই বাস্তবায়ন কি একাধিক লেখকের জন্য থ্রেডসফ? যদি তা না হয় তবে এটিকে একটি রিডসেইফলিস্ট বলা উচিত।
মাইক ওয়ার্ড

5
@ মাইক ওয়ার্ড - আমি মনে করি এটি হওয়া উচিত নয়, যখন কোনও উদাহরণ ক্লোন করা হচ্ছে তখন সমস্ত উদাহরণ লক হয়ে যাবে !
জোশ এম

11

এমনকি স্বীকৃত উত্তরটি কনকন্টারব্যাগ, আমি মনে করি না যে এটি সমস্ত ক্ষেত্রে তালিকার আসল প্রতিস্থাপন, কারণ উত্তরে রাদেকের মন্তব্য বলেছে: "কনকন্টেন্টব্যাগ আনর্ডারড সংগ্রহ, সুতরাং তালিকার বিপরীতে এটি অর্ডার দেওয়ার গ্যারান্টি দেয় না index এছাড়াও আপনি সূচী দ্বারা আইটেমগুলিতে অ্যাক্সেস করতে পারবেন না I "।

তাই আপনি যদি .NET 4.0 বা উচ্চতর ব্যবহার করেন, একটি ওয়ার্কঅ্যারাউন্ড ব্যবহার করতে হতে পারে ConcurrentDictionary অ্যারের সূচক ও TValue অ্যারের মান হিসাবে হিসাবে পূর্ণসংখ্যা TKey সঙ্গে। এটি Pluralsight এর সি # সমকালীন সংগ্রহের কোর্সে তালিকা প্রতিস্থাপনের উপায় হিসাবে প্রস্তাবিত । সমকালীন অভিধান অভিধান উল্লিখিত উভয় সমস্যার সমাধান করে: সূচী অ্যাক্সেস এবং অর্ডারিং (আমরা এটির হুডের নীচে হ্যাশ টেবিল হিসাবে অর্ডার দেওয়ার উপর নির্ভর করতে পারি না, তবে বর্তমান। নেট বাস্তবায়ন উপাদানগুলির যোগ করার ক্রম সংরক্ষণ করে)।


1
দয়া করে -1
tytyryty

আমি ভোট কম করি নি এবং এর আইএমও করার কোনও কারণ নেই। আপনি ঠিক বলেছেন তবে ইতিমধ্যে কয়েকটি উত্তরে ধারণাটি উল্লেখ করা হয়েছে। আমার কাছে কথাটি ছিল যে .NET 4.0 এ একটি নতুন থ্রেড-নিরাপদ সংগ্রহ রয়েছে যা সম্পর্কে আমি অবগত ছিল না। পরিস্থিতির জন্য ব্যাগ বা সংগ্রহটি নিশ্চিতভাবে ব্যবহার করা হয়নি। +1
Xaqron

2
এই উত্তরের বেশ কয়েকটি সমস্যা রয়েছে: 1) ConcurrentDictionaryএকটি অভিধান, কোনও তালিকা নয়। ২) এটি সংরক্ষণকারীর অর্ডার দেওয়ার কোনও গ্যারান্টিযুক্ত নয়, কারণ আপনার নিজের উত্তরতে বলা হয়েছে, যা উত্তর পোস্ট করার জন্য আপনার উল্লিখিত কারণের সাথে বিরোধী। 3) এটি এই উত্তরটিতে প্রাসঙ্গিক উদ্ধৃতি না নিয়ে কোনও ভিডিওর সাথে লিঙ্ক করে (এটি যাইহোক তাদের লাইসেন্সের সাথে একমত হতে পারে না)।
jpmc26

আপনি current implementationডকুমেন্টেশন দ্বারা স্পষ্টভাবে গ্যারান্টিযুক্ত না হলে যেমন আপনি উপর নির্ভর করতে পারবেন না । বাস্তবায়ন কোনও বিজ্ঞপ্তি ছাড়াই যে কোনও সময় পরিবর্তন হতে পারে।
ভিক্টর ইয়ারেমা

@ jpmc26, হ্যাঁ এটি অবশ্যই তালিকার সম্পূর্ণ প্রতিস্থাপন নয়, তবে এটি একটি স্বীকৃত উত্তর হিসাবে কনকন্টার ব্যাগের সাথে একই - এটি তালিকার কঠোর প্রতিস্থাপন নয় তবে কাজ করা। আপনার উদ্বেগের জবাব দেওয়ার জন্য: ১) সাম্প্রতিক অভিধান অভিধান একটি অভিধান যা আপনার ঠিক ঠিক নয়, তবে তালিকার পিছনে অ্যারে রয়েছে, যা O (1) তে সূচক করতে পারে মূল হিসাবে 2 এর সাথে ডিকশনারি হিসাবে) হ্যাঁ অর্ডার ডক দ্বারা গ্যারান্টিযুক্ত নয় ( যদিও এটি সংরক্ষিত রয়েছে), তবে স্বীকৃত
কনক্রন্টব্যাগটি

9

সি # এর ArrayListশ্রেণিতে একটি Synchronizedপদ্ধতি রয়েছে।

var threadSafeArrayList = ArrayList.Synchronized(new ArrayList());

এটি যেকোন উদাহরণের চারপাশে একটি থ্রেড নিরাপদ মোড়কে দেয় IList। থ্রেড সুরক্ষা নিশ্চিত করার জন্য সমস্ত অপারেশন মোড়কের মাধ্যমে সম্পাদন করা প্রয়োজন।


1
আপনি কোন ভাষায় কথা বলছেন?
জন ডেমেট্রিও

জাভা? আমি এটি মিস করেছি কয়েকটি বৈশিষ্ট্যগুলির একটি। তবে এটি সাধারণত হিসাবে লিখিত হয়: কালেকশন.সিনক্রোনাইজডলিস্ট (নতুন অ্যারেলিস্ট ());
নিক 21

2
এটি আপনার বৈধ সি # ধরে ধরে নেওয়া হচ্ছে যে আপনার সিস্টেম.কলেকশন রয়েছে or বা আপনি বিভিন্ন সিস্টেম ব্যবহার করতে পারেন Col
ব্যবহারকারী 2163234

5

আপনি যদি তালিকার টি ( https: //references Source.microsoft.com/#mscorlib/system/collections/generic/list.cs,c66df6f36c131877 ) এর উত্স কোডটি দেখেন তবে আপনি দেখতে পাবেন যে সেখানে একটি শ্রেণি রয়েছে (যা অবশ্যই অভ্যন্তরীণ - কেন, মাইক্রোসফ্ট, কেন?!?!) সিঙ্ক্রোনাইজড লিস্ট অফ টি। আমি কোডটি এখানে আটকানো কপি করছি:

   [Serializable()]
    internal class SynchronizedList : IList<T> {
        private List<T> _list;
        private Object _root;

        internal SynchronizedList(List<T> list) {
            _list = list;
            _root = ((System.Collections.ICollection)list).SyncRoot;
        }

        public int Count {
            get {
                lock (_root) { 
                    return _list.Count; 
                }
            }
        }

        public bool IsReadOnly {
            get {
                return ((ICollection<T>)_list).IsReadOnly;
            }
        }

        public void Add(T item) {
            lock (_root) { 
                _list.Add(item); 
            }
        }

        public void Clear() {
            lock (_root) { 
                _list.Clear(); 
            }
        }

        public bool Contains(T item) {
            lock (_root) { 
                return _list.Contains(item);
            }
        }

        public void CopyTo(T[] array, int arrayIndex) {
            lock (_root) { 
                _list.CopyTo(array, arrayIndex);
            }
        }

        public bool Remove(T item) {
            lock (_root) { 
                return _list.Remove(item);
            }
        }

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

        IEnumerator<T> IEnumerable<T>.GetEnumerator() {
            lock (_root) { 
                return ((IEnumerable<T>)_list).GetEnumerator();
            }
        }

        public T this[int index] {
            get {
                lock(_root) {
                    return _list[index];
                }
            }
            set {
                lock(_root) {
                    _list[index] = value;
                }
            }
        }

        public int IndexOf(T item) {
            lock (_root) {
                return _list.IndexOf(item);
            }
        }

        public void Insert(int index, T item) {
            lock (_root) {
                _list.Insert(index, item);
            }
        }

        public void RemoveAt(int index) {
            lock (_root) {
                _list.RemoveAt(index);
            }
        }
    }

ব্যক্তিগতভাবে আমি মনে করি তারা জানত যে সেমফোরস্লিম ব্যবহার করে আরও কার্যকর বাস্তবায়ন তৈরি করা যেতে পারে, তবে তা পেতে পারেনি।


2
+1 _rootপ্রতিটি অ্যাক্সেসে ( পুরোপুরি সংগ্রহটি ) লক করা (পড়ুন / লিখুন) এটি একটি ধীর সমাধান করে তোলে। সম্ভবত এই শ্রেণীর অভ্যন্তরীণ থাকা ভাল।
Xaqron

3
এই বাস্তবায়ন থ্রেড-নিরাপদ নয়। এটা এখনও ছোঁড়ার "System.InvalidOperationException: 'সংগ্রহ পরিবর্তিত হয়; শুমার অপারেশন চালানো নাও হতে পারে।'"
রমন Zhylich

2
এটি থ্রেড সুরক্ষার সাথে সম্পর্কিত নয়, তবে আপনি পুনরাবৃত্তি করছেন এবং সংগ্রহটি পরিবর্তন করছেন। তালিকাটি পরিবর্তন করা হয়েছে দেখে গণকরা ব্যতিক্রম নিক্ষেপ করেছেন। এটি কাছাকাছি পেতে আপনার নিজের আইনিমেটর বাস্তবায়ন করতে হবে বা কোডটি পরিবর্তন করতে হবে যাতে এটি পুনরায় না হয় এবং একই সময়ে একই সংগ্রহটি পরিবর্তন করে না।
সিডারাইট জ্যাকওয়ার্ডেডেক্স

এটি থ্রেড-নিরাপদ নয় কারণ "সিঙ্ক্রোনাইজড" পদ্ধতির সময় সংগ্রহটি পরিবর্তন করা যেতে পারে। যে একেবারে হয় থ্রেড নিরাপত্তা অংশ। Clear()অন্য কলগুলির পরে একটি থ্রেড কল বিবেচনা করুন তবে this[index]লকটি সক্রিয় হওয়ার আগে। indexব্যবহার করা আর নিরাপদ নয় এবং অবশেষে এটি কার্যকর হলে একটি ব্যতিক্রম ছুঁড়ে ফেলবে।
সানক্যাট 2000 হাজার

2

আপনি আরও আদিম ব্যবহার করতে পারেন

Monitor.Enter(lock);
Monitor.Exit(lock);

কোন লকটি ব্যবহার করে (এই পোস্টটি দেখুন # লক ব্লকে পুনরায় নিযুক্ত একটি বস্তুকে লক করা )।

আপনি যদি কোডটিতে ব্যতিক্রম প্রত্যাশা করে থাকেন তবে এটি নিরাপদ নয় তবে এটি আপনাকে নিম্নলিখিতগুলির মতো কিছু করতে দেয়:

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

public class Something
{
    private readonly object _lock;
    private readonly List<string> _contents;

    public Something()
    {
        _lock = new object();

        _contents = new List<string>();
    }

    public Modifier StartModifying()
    {
        return new Modifier(this);
    }

    public class Modifier : IDisposable
    {
        private readonly Something _thing;

        public Modifier(Something thing)
        {
            _thing = thing;

            Monitor.Enter(Lock);
        }

        public void OneOfLotsOfDifferentOperations(string input)
        {
            DoSomethingWith(input);
        }

        private void DoSomethingWith(string input)
        {
            Contents.Add(input);
        }

        private List<string> Contents
        {
            get { return _thing._contents; }
        }

        private object Lock
        {
            get { return _thing._lock; }
        }

        public void Dispose()
        {
            Monitor.Exit(Lock);
        }
    }
}

public class Caller
{
    public void Use(Something thing)
    {
        using (var modifier = thing.StartModifying())
        {
            modifier.OneOfLotsOfDifferentOperations("A");
            modifier.OneOfLotsOfDifferentOperations("B");

            modifier.OneOfLotsOfDifferentOperations("A");
            modifier.OneOfLotsOfDifferentOperations("A");
            modifier.OneOfLotsOfDifferentOperations("A");
        }
    }
}

এটি সম্পর্কে একটি দুর্দান্ত জিনিস হ'ল আপনি ক্রমের ক্রমটির সময়কালের জন্য লক পাবেন (প্রতিটি ক্রিয়াকলাপে লক না করে)। যার অর্থ হ'ল আউটপুটটি সঠিক অংশগুলিতে বের হওয়া উচিত (এটির আমার ব্যবহারটি কোনও বাহ্যিক প্রক্রিয়া থেকে স্ক্রিনে কিছু আউটপুট পাচ্ছিল)

আমি থ্রেডস্যাফলিস্টের সরলতা + স্বচ্ছতা + পছন্দ করি যা ক্র্যাশ বন্ধে গুরুত্বপূর্ণ কাজ করে


2

.NET কোর (যে কোনও সংস্করণ) এ, আপনি ImmutableList ব্যবহার করতে পারেন , যার সমস্ত কার্যকারিতা রয়েছে List<T>


1

আমি বিশ্বাস করি _list.ToList()আপনাকে একটি অনুলিপি তৈরি করবে। আপনার যদি প্রয়োজন হয় তবে আপনি এটি সম্পর্কে জিজ্ঞাসাও করতে পারেন:

_list.Select("query here").ToList(); 

যাইহোক, এমএসডিএন বলছে এটি আসলে একটি অনুলিপি এবং কেবল কোনও রেফারেন্স নয়। ওহ, এবং হ্যাঁ, অন্যরা যেমন উল্লেখ করেছে তেমনভাবে আপনাকে সেট পদ্ধতিতে লক করতে হবে।


1

দেখে মনে হচ্ছে এটির সন্ধানকারী অনেকেই একটি থ্রেড নিরাপদ সূচকযুক্ত গতিশীল আকারের সংগ্রহ চান। আমার জানা সবচেয়ে কাছের এবং সহজ জিনিসটি হ'ল।

System.Collections.Concurrent.ConcurrentDictionary<int, YourDataType>

এটির জন্য আপনার চাবিটি যথাযথভাবে জড়িত কিনা তা নিশ্চিত করা দরকার যদি আপনি স্বাভাবিক সূচক আচরণ চান। আপনি যদি সাবধান হন তবে অ্যাকাউন্টটি যুক্ত করা কোনও নতুন মূল্যের জোড়গুলির মূল হিসাবে যথেষ্ট হতে পারে।


1
কীটির চাবিটি যখন ত্রুটি ছিল না তখন তাকে কেন ক্ষতিগ্রস্থ করা উচিত?
সানকাট 2000

@ সানক্যাট 2000 হাজার!
রিচার্ড দ্বিতীয়

1

আমি সঙ্গে তার আচরণ যে কেউ সুপারিশ করবে List<T>এ দেখে নিতে বহু-থ্রেডিং পরিস্থিতিতে অপরিবর্তনীয় সংগ্রহগুলি বিশেষ করে ImmutableArray

আপনি যখন পেয়েছেন তখন আমি এটি খুব দরকারী পেয়েছি:

  1. তুলনামূলকভাবে তালিকার কয়েকটি আইটেম
  2. এত বেশি পড়া / লেখার কাজ নয়
  3. প্রচুর একযোগে অ্যাক্সেস (অর্থাত্ অনেকগুলি থ্রেড যা তালিকায় পঠন মোডে অ্যাক্সেস করে)

এছাড়াও যখন আপনার কোনও ধরণের লেনদেনের মতো আচরণ বাস্তবায়নের প্রয়োজন হয় (যেমন ব্যর্থতার ক্ষেত্রে সন্নিবেশ / আপডেট / অপসারণ অপারেশনটি পুনরায়)


-1

আপনি যে ক্লাসটি চেয়েছিলেন তা এখানে:

namespace AI.Collections {
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Linq;
    using System.Runtime.Serialization;
    using System.Threading.Tasks;
    using System.Threading.Tasks.Dataflow;

    /// <summary>
    ///     Just a simple thread safe collection.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <value>Version 1.5</value>
    /// <remarks>TODO replace locks with AsyncLocks</remarks>
    [DataContract( IsReference = true )]
    public class ThreadSafeList<T> : IList<T> {
        /// <summary>
        ///     TODO replace the locks with a ReaderWriterLockSlim
        /// </summary>
        [DataMember]
        private readonly List<T> _items = new List<T>();

        public ThreadSafeList( IEnumerable<T> items = null ) { this.Add( items ); }

        public long LongCount {
            get {
                lock ( this._items ) {
                    return this._items.LongCount();
                }
            }
        }

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

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

        public void Add( T item ) {
            if ( Equals( default( T ), item ) ) {
                return;
            }
            lock ( this._items ) {
                this._items.Add( item );
            }
        }

        public Boolean TryAdd( T item ) {
            try {
                if ( Equals( default( T ), item ) ) {
                    return false;
                }
                lock ( this._items ) {
                    this._items.Add( item );
                    return true;
                }
            }
            catch ( NullReferenceException ) { }
            catch ( ObjectDisposedException ) { }
            catch ( ArgumentNullException ) { }
            catch ( ArgumentOutOfRangeException ) { }
            catch ( ArgumentException ) { }
            return false;
        }

        public void Clear() {
            lock ( this._items ) {
                this._items.Clear();
            }
        }

        public bool Contains( T item ) {
            lock ( this._items ) {
                return this._items.Contains( item );
            }
        }

        public void CopyTo( T[] array, int arrayIndex ) {
            lock ( this._items ) {
                this._items.CopyTo( array, arrayIndex );
            }
        }

        public bool Remove( T item ) {
            lock ( this._items ) {
                return this._items.Remove( item );
            }
        }

        public int Count {
            get {
                lock ( this._items ) {
                    return this._items.Count;
                }
            }
        }

        public bool IsReadOnly { get { return false; } }

        public int IndexOf( T item ) {
            lock ( this._items ) {
                return this._items.IndexOf( item );
            }
        }

        public void Insert( int index, T item ) {
            lock ( this._items ) {
                this._items.Insert( index, item );
            }
        }

        public void RemoveAt( int index ) {
            lock ( this._items ) {
                this._items.RemoveAt( index );
            }
        }

        public T this[ int index ] {
            get {
                lock ( this._items ) {
                    return this._items[ index ];
                }
            }
            set {
                lock ( this._items ) {
                    this._items[ index ] = value;
                }
            }
        }

        /// <summary>
        ///     Add in an enumerable of items.
        /// </summary>
        /// <param name="collection"></param>
        /// <param name="asParallel"></param>
        public void Add( IEnumerable<T> collection, Boolean asParallel = true ) {
            if ( collection == null ) {
                return;
            }
            lock ( this._items ) {
                this._items.AddRange( asParallel
                                              ? collection.AsParallel().Where( arg => !Equals( default( T ), arg ) )
                                              : collection.Where( arg => !Equals( default( T ), arg ) ) );
            }
        }

        public Task AddAsync( T item ) {
            return Task.Factory.StartNew( () => { this.TryAdd( item ); } );
        }

        /// <summary>
        ///     Add in an enumerable of items.
        /// </summary>
        /// <param name="collection"></param>
        public Task AddAsync( IEnumerable<T> collection ) {
            if ( collection == null ) {
                throw new ArgumentNullException( "collection" );
            }

            var produce = new TransformBlock<T, T>( item => item, new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = Environment.ProcessorCount } );

            var consume = new ActionBlock<T>( action: async obj => await this.AddAsync( obj ), dataflowBlockOptions: new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = Environment.ProcessorCount } );
            produce.LinkTo( consume );

            return Task.Factory.StartNew( async () => {
                collection.AsParallel().ForAll( item => produce.SendAsync( item ) );
                produce.Complete();
                await consume.Completion;
            } );
        }

        /// <summary>
        ///     Returns a new copy of all items in the <see cref="List{T}" />.
        /// </summary>
        /// <returns></returns>
        public List<T> Clone( Boolean asParallel = true ) {
            lock ( this._items ) {
                return asParallel
                               ? new List<T>( this._items.AsParallel() )
                               : new List<T>( this._items );
            }
        }

        /// <summary>
        ///     Perform the <paramref name="action" /> on each item in the list.
        /// </summary>
        /// <param name="action">
        ///     <paramref name="action" /> to perform on each item.
        /// </param>
        /// <param name="performActionOnClones">
        ///     If true, the <paramref name="action" /> will be performed on a <see cref="Clone" /> of the items.
        /// </param>
        /// <param name="asParallel">
        ///     Use the <see cref="ParallelQuery{TSource}" /> method.
        /// </param>
        /// <param name="inParallel">
        ///     Use the
        ///     <see
        ///         cref="Parallel.ForEach{TSource}(System.Collections.Generic.IEnumerable{TSource},System.Action{TSource})" />
        ///     method.
        /// </param>
        public void ForEach( Action<T> action, Boolean performActionOnClones = true, Boolean asParallel = true, Boolean inParallel = false ) {
            if ( action == null ) {
                throw new ArgumentNullException( "action" );
            }
            var wrapper = new Action<T>( obj => {
                try {
                    action( obj );
                }
                catch ( ArgumentNullException ) {
                    //if a null gets into the list then swallow an ArgumentNullException so we can continue adding
                }
            } );
            if ( performActionOnClones ) {
                var clones = this.Clone( asParallel: asParallel );
                if ( asParallel ) {
                    clones.AsParallel().ForAll( wrapper );
                }
                else if ( inParallel ) {
                    Parallel.ForEach( clones, wrapper );
                }
                else {
                    clones.ForEach( wrapper );
                }
            }
            else {
                lock ( this._items ) {
                    if ( asParallel ) {
                        this._items.AsParallel().ForAll( wrapper );
                    }
                    else if ( inParallel ) {
                        Parallel.ForEach( this._items, wrapper );
                    }
                    else {
                        this._items.ForEach( wrapper );
                    }
                }
            }
        }

        /// <summary>
        ///     Perform the <paramref name="action" /> on each item in the list.
        /// </summary>
        /// <param name="action">
        ///     <paramref name="action" /> to perform on each item.
        /// </param>
        /// <param name="performActionOnClones">
        ///     If true, the <paramref name="action" /> will be performed on a <see cref="Clone" /> of the items.
        /// </param>
        /// <param name="asParallel">
        ///     Use the <see cref="ParallelQuery{TSource}" /> method.
        /// </param>
        /// <param name="inParallel">
        ///     Use the
        ///     <see
        ///         cref="Parallel.ForEach{TSource}(System.Collections.Generic.IEnumerable{TSource},System.Action{TSource})" />
        ///     method.
        /// </param>
        public void ForAll( Action<T> action, Boolean performActionOnClones = true, Boolean asParallel = true, Boolean inParallel = false ) {
            if ( action == null ) {
                throw new ArgumentNullException( "action" );
            }
            var wrapper = new Action<T>( obj => {
                try {
                    action( obj );
                }
                catch ( ArgumentNullException ) {
                    //if a null gets into the list then swallow an ArgumentNullException so we can continue adding
                }
            } );
            if ( performActionOnClones ) {
                var clones = this.Clone( asParallel: asParallel );
                if ( asParallel ) {
                    clones.AsParallel().ForAll( wrapper );
                }
                else if ( inParallel ) {
                    Parallel.ForEach( clones, wrapper );
                }
                else {
                    clones.ForEach( wrapper );
                }
            }
            else {
                lock ( this._items ) {
                    if ( asParallel ) {
                        this._items.AsParallel().ForAll( wrapper );
                    }
                    else if ( inParallel ) {
                        Parallel.ForEach( this._items, wrapper );
                    }
                    else {
                        this._items.ForEach( wrapper );
                    }
                }
            }
        }
    }
}

ক্লাসটি আপডেট করার সাথে সাথে Google ড্রাইভের সংস্করণ আপডেট হবে। uberscraper.blogspot.com/2012/12/c-thread-safe-list.html
প্রতিবাদী

this.GetEnumerator();@ টিজস যখন পরামর্শ দেয় কেন this.Clone().GetEnumerator();?
সিউর

কেন [DataContract( IsReference = true )]?
সিউর

সর্বশেষতম সংস্করণটি এখন গিটহাবে রয়েছে! github.com/AIBrain/Librain/blob/master/ Collections/…
প্রতিবাদী

আমি অ্যাড () পদ্ধতিতে দুটি ছোট বাগ খুঁজে পেয়েছি এবং ঠিক করেছি। অবগতির জন্য।
প্রতিলিপি

-2

লক ছাড়াই থ্রেড নিরাপদ তালিকার ক্লাস এখানে

 public class ConcurrentList   
    {
        private long _i = 1;
        private ConcurrentDictionary<long, T> dict = new ConcurrentDictionary<long, T>();  
        public int Count()
        {
            return dict.Count;
        }
         public List<T> ToList()
         {
            return dict.Values.ToList();
         }

        public T this[int i]
        {
            get
            {
                long ii = dict.Keys.ToArray()[i];
                return dict[ii];
            }
        }
        public void Remove(T item)
        {
            T ov;
            var dicItem = dict.Where(c => c.Value.Equals(item)).FirstOrDefault();
            if (dicItem.Key > 0)
            {
                dict.TryRemove(dicItem.Key, out ov);
            }
            this.CheckReset();
        }
        public void RemoveAt(int i)
        {
            long v = dict.Keys.ToArray()[i];
            T ov;
            dict.TryRemove(v, out ov);
            this.CheckReset();
        }
        public void Add(T item)
        {
            dict.TryAdd(_i, item);
            _i++;
        }
        public IEnumerable<T> Where(Func<T, bool> p)
        {
            return dict.Values.Where(p);
        }
        public T FirstOrDefault(Func<T, bool> p)
        {
            return dict.Values.Where(p).FirstOrDefault();
        }
        public bool Any(Func<T, bool> p)
        {
            return dict.Values.Where(p).Count() > 0 ? true : false;
        }
        public void Clear()
        {
            dict.Clear();
        }
        private void CheckReset()
        {
            if (dict.Count == 0)
            {
                this.Reset();
            }
        }
        private void Reset()
        {
            _i = 1;
        }
    }

এটি থ্রেডসেফ নয়
অলড্রাকর

-3

মূলত আপনি যদি নিরাপদে গণনা করতে চান তবে আপনাকে লক ব্যবহার করতে হবে।

দয়া করে এটিতে এমএসডিএন দেখুন। http://msdn.microsoft.com/en-us/library/6sh2ey19.aspx

এখানে এমএসডিএন এর অংশ যা আপনার আগ্রহী হতে পারে:

এই ধরণের সদস্য পাবলিক স্ট্যাটিক (ভিজ্যুয়াল বেসিকের মধ্যে ভাগ করা) থ্রেড নিরাপদ। কোনও উদাহরণ সদস্যদের থ্রেড নিরাপদ থাকার গ্যারান্টি নেই।

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


2
মোটেও সত্য নয়। আপনি সমবর্তী সেট ব্যবহার করতে পারেন।
এভিনিস

-15

এটি করতে lockবিবৃতিটি ব্যবহার করুন । ( আরও তথ্যের জন্য এখানে পড়ুন। )

private List<T> _list;

private List<T> MyT
{
    get { return _list; }
    set
    {
        //Lock so only one thread can change the value at any given time.
        lock (_list)
        {
            _list = value;
        }
    }
}

এফওয়াইআই সম্ভবত আপনার জিজ্ঞাসাটি ঠিক তেমন নয় - আপনি সম্ভবত আপনার কোডটি আরও লক করতে চান তবে আমি এটি ধরে নিতে পারি না। একবার দেখুনlockকীওয়ার্ডটি আপনার নির্দিষ্ট পরিস্থিতির জন্য এটির ব্যবহারটি তৈরি করুন।

আপনার যদি প্রয়োজন হয় তবে আপনি ভেরিয়েবলটি ব্যবহার করে ব্লক এবং ব্লক lockউভয় ক্ষেত্রেই করতে পারেন যা এটি একই সাথে একটি পঠন / লেখার ঘটনা ঘটতে পারে না।getset_list


1
এটি তার সমস্যার সমাধান করতে যাচ্ছে না; এটি কেবল থ্রেডগুলিকে রেফারেন্স সেট করা থেকে থামায়, তালিকায় যুক্ত না করে।
তেজস

এবং যদি কোনও থ্রেড মান নির্ধারণ করে যখন অন্যটি সংগ্রহে পুনরাবৃত্তি করে (আপনার কোড দিয়ে এটি সম্ভব) what
Xaqron

আমি যেমন বলেছি, সম্ভবত কোডটিতে লকটি আরও বাইরে নিয়ে যেতে হবে। এটি কীভাবে লক স্টেটমেন্টটি ব্যবহার করবেন তার একটি উদাহরণ।
জোশ এম।

2
@ জোয়েল মুয়েলার: অবশ্যই, আপনি যদি এর মতো নির্লজ্জ উদাহরণ প্রস্তুত করেন। আমি কেবল এটিই বোঝানোর চেষ্টা করছি যে প্রশ্নকারীর lockবক্তব্যটি সন্ধান করা উচিত । একটি অনুরূপ উদাহরণ ব্যবহার করে আমি তর্ক করতে পারি যে আমাদের লুপগুলির জন্য ব্যবহার করা উচিত নয় যেহেতু আপনি খুব কম চেষ্টা করেই অ্যাপ্লিকেশনটি অচল করতে পারেন:for (int x = 0; x >=0; x += 0) { /* Infinite loop, oops! */ }
জোশ এম এম

5
আমি কখনও আপনার কোড মানে তাত্ক্ষণিক অচলাবস্থা দাবি করিনি। এটি নিম্নলিখিত কারণে এই নির্দিষ্ট প্রশ্নের একটি খারাপ উত্তর: 1) তালিকাটি তালিকাবদ্ধকরণের সময় সংশোধিত হওয়ার পরে বা একবারে দুটি থ্রেডের দ্বারা সুরক্ষিত করে না। 2) সেটারটি লক করা তবে গেটর নয় মানে সম্পত্তিটি আসলে থ্রেড-নিরাপদ নয়। 3) শ্রেণীর বাইরে থেকে অ্যাক্সেসযোগ্য যে কোনও রেফারেন্সে লক করা ব্যাপকভাবে একটি খারাপ অভ্যাস হিসাবে বিবেচিত হয়, কারণ এটি নাটকীয়ভাবে দুর্ঘটনাজনিত অচলাবস্থার সম্ভাবনা বাড়িয়ে তোলে। এ কারণেই lock (this)এবং lock (typeof(this))তারা বড় নো-হ'ল।
জোয়েল মুলার
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.