Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ConcurrentBag Alternative In Portable Class Library

I have an application that has a list of objects stored in a static ConcurrentBag.

The UI has a timer that runs methods that can update the objects in the ConcurrentBag.

Only one thread (Started by the timer) will try to update these objects. However, this thread will enumerate through the list and then update the items as it goes.

At the same time these objects can be read by the UI thread.

ConcurrentBag is working perfectly for what I want to do. All the business logic is in a separate project and I now need to port everything to iOS and Android. I'm doing this with Xamarin and so am converting the business logic into a Portable Class Library.

Although everything I'm targeting appears to support ConcurrentBag, when I try to access it in a PCL, System.Collections.Concurrent is not available. Even if I only target .net 4.5 and above + windows store apps (Both of which I have used ConcurrentBags for)

Is there another alternative to ConcurrentBag or am I better off just creating separate projects for each targeted system?

like image 261
Oli Avatar asked Apr 28 '14 16:04

Oli


People also ask

When to use ConcurrentBag c#?

ConcurrentBag allows you to store objects in unordered way. Contrary to ConcurrentDictionary class, it allows you to store duplicate objects. ConcurrentBag allows multiple threads to store the objects. It is optimized for scenarios where same thread act as producer and consumer.

What is concurrent bag?

Bags are useful for storing objects when ordering doesn't matter, and unlike sets, bags support duplicates. ConcurrentBag<T> is a thread-safe bag implementation, optimized for scenarios where the same thread will be both producing and consuming data stored in the bag.


1 Answers

Well, if the obvious won't work, you have several options here. First, is to decompile ConcurrentBag and use that code. Second, is to come up with a replacement. It's my estimate that you in your specific case don't necessarily need the performance guarantees and ordering issues of a ConcurrentBag... So, this is a working example of what would fit your bill:

namespace Naive
{
    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;

    public class ThreadSafeCollectionNaive<T>
    {
        private readonly List<T> _list = new List<T>();
        private readonly object _criticalSection = new object();

        /// <summary>
        /// This is consumed in the UI. This is O(N)
        /// </summary>
        public ReadOnlyCollection<T> GetContentsCopy()
        {
            lock (_criticalSection)
            {
                return new List<T>(_list).AsReadOnly();
            }
        }

        /// <summary>
        /// This is a hacky way to handle updates, don't want to write lots of code
        /// </summary>
        public void Update(Action<List<T>> workToDoInTheList)
        {
            if (workToDoInTheList == null) throw new ArgumentNullException("workToDoInTheList");

            lock (_criticalSection)
            {
                workToDoInTheList.Invoke(_list);
            }
        }

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

        // Add more members as you see fit
    }

    class Program
    {
        static void Main(string[] args)
        {
            var collectionNaive = new ThreadSafeCollectionNaive<string>();

            collectionNaive.Update((l) => l.AddRange(new []{"1", "2", "3"}));

            collectionNaive.Update((l) =>
                                       {
                                           for (int i = 0; i < l.Count; i++)
                                           {
                                               if (l[i] == "1")
                                               {
                                                   l[i] = "15";
                                               }
                                           }
                                       });
        }
    }
}
like image 113
Mikhail Avatar answered Oct 16 '22 09:10

Mikhail