Une classe zone_transit

Des explications suivront quand j'aurai un peu plus de temps. Notez qu'il serait possible d'aller plus loin en définissant une liste sans verrous.

Notez que j'ai utilisé du code C++ 17 pour alléger l'écriture en profitant de CTAD; si votre compilateur n'est pas à jour, remplacez lock_guard et unique_lock par lock_guard<mutex> et unique_lock<mutex> dans les exemples.

Version simple

Cette version ne laisse circuler que des chaînes de caractères.

#include <string>
#include <mutex>
class zone_transit {
public:
   using value_type = std::string;
private:
   value_type texte;
   std::mutex m;
public:
   void ajouter(const value_type &s) {
      using namespace std;
      lock_guard _ { m };
      texte += s;
   }
   value_type extraire() {
      value_type s;
      using namespace std;
      {
         lock_guard _ { m };
         s.swap(texte);
      }
      return s;
   }
};

Si on tient compte de la qualification volatile, on a :

#include <string>
#include <mutex>
class zone_transit {
public:
   using value_type = std::string;
private:
   value_type texte;
   std::mutex m;
   auto verrouiller() const volatile {
      return std::unique_lock { const_cast<mutex&>(m) };
   }
public:
   void ajouter(const value_type &s) volatile {
      auto verrou = verrouiller();
      const_cast<zone_transit&>(*this).ajouter(s);
   }
   void ajouter(const value_type &s) {
      texte += s;
   }
   value_type extraire() {
      value_type s;
      s.swap(texte);
      return s;
   }
   value_type extraire() volatile {
      auto verrou = verrouiller();
      return const_cast<zone_transit&>(*this).extraire();
   }
};

Version plus riche

Cette version fait circuler des instances d'un certain type T.

#include <mutex>
#include <vector>
template <class T>
   class zone_transit {
   public:
      using value_type = T;
   private:
      std::vector<T> data;
      std::mutex m;
   public:
      template <class It>
         void ajouter(It debut, It fin) {
            using namespace std;
            lock_guard _ { m };
            data.insert(data.end(), debut, fin);
         }
      auto extraire() {
         using namespace std;
         vector<T> vals;
         {
            lock_guard _ { m };
            vals.swap(data);
         }
         return vals;
      }
   };

Voilà.

Exemple en C#

Un équivalent approximatif en C# pourrait être comme suit (mais prudence avec les risques d'alias sur des objets mutables, possibles aussi en C++ mais plus fréquemment rencontrés dans un langage comme C# où les objets ne sont accédés qu'indirectement). Pour une version naïve :

using System.Collections.Generic;
class ZoneTransit<T>
{
   List<T> Data { get; set; } = new List<T>();
   object Mutex { get; } = new object();
   public Ajouter(List<T> src)
   {
      lock(Mutex)
      {
         foreach(T obj in src)
            Data.Add(obj);
      }
   }
   public List<T> Extraire()
   {
      var rés = new List<T>();
      lock(mutex)
      {
         foreach(T obj in Data)
            rés.Add(obj);
      }
      return rés;
   }
}

... et pour une version moins naïve :

using System.Collections.Generic;
static class Algos
{
   public static Swap<T>(ref T a, ref T b)
   {
      T temp = a;
      a = b;
      b = temp;
   }
}
class ZoneTransit<T>
{
   List<T> Data { get; set; } = new List<T>();
   object Mutex { get; } = new object();
   public Ajouter(List<T> src)
   {
      lock(Mutex)
      {
         Data.AddRange(src);
      }
   }
   public List<T> Extraire()
   {
      var rés = new List<T>();
      lock(mutex)
      {
         Algos.Swap(ref Data, ref rés);
      }
      return rés;
   }
}

Valid XHTML 1.0 Transitional

CSS Valide !