2017-07-03 3 views
0

C++ Mon code a une structure de données disent par exemple « vecteur de vecor de chaînes que j'ai 2 fils:multithreading et ressources partagées. Copier périodiquement les données de tampon (structure de données) à un fichier en utilisant

Enfilez 1 est en train d'écrire des données sur cette structure de données (tampon dans la RAM).

discussion 2 en cours d'exécution en parallèle qui devrait copier les données de la structure de données par exemple tampon ci-dessus un fichier pour chaque « x » miliseconds.

I Je me demande comment pourrais-je réaliser cela en C++? Il devrait considérer la clé points dans l'énoncé du problème comme:

a) La copie du tampon vers le fichier ne devrait se produire qu'une seule fois en "X" milisecondes.

b) Synchronisation entre les deux threads.

TRAITEMENT DE LA REQUETE AVEC PLUS DE DÉTAILS PAR LE DEMANDER

Je veux construire une bibliothèque (* .lib) & cette bibliothèque expose des API d'où il obtient des données d'entrée à partir EXE ou toute entité qui utilise ma bibliothèque à travers ces API. Dites que les données reçues par ma bibliothèque sont sous la forme d'un vecteur de chaînes.

FillLibraryDataStructure(std::vector<std::string>); // is the API of this library. Any app can call this API & pass a vector of string to this library. 

Example app code: 
for(int i=100; i<100;i)) 
{ 
std::vector<std::string> vec = GetVectorOfString(); // GetVectorOfString from business logic 
FillLibraryDataStructure(vec); 
} 

Code Library havin une ressource partagée:

// Within library I've a 2D vector i.e. vector of vector of 
strings where all the vector of strings passed by application to this librray are added as a new row in vecofvecofstr. 

RESSOURCES PARTAGÉE:

std::vector<std::vector<string>> vecofvecofstr; 

FILET 1: est la copie des données qu'il rece ives de l'API à la structure de données, c'est-à-dire le vecteur du vecteur des chaînes.

vecofvecofstr.push_back(vec); 

FILET 2: est la copie du contenu de ce vecteur de vecteur de chaîne (qui a été écrit dans le 1er fil) aux fichiers (XML, HTML, etc ..) pour tous les "X" miiliseconds.

quelques points sur thread1: 1) Sujet 1 doivent être en cours d'exécution en continu à savoir que lorsque l'application et appelle l'API les données reçus doivent être mis à la structure de données vecofvecofstr. 2) Après "X" miliseonds de la copie des données dans le tampon, 2ème thread doit commencer à & devrait copier tous les trucs qui ont été jetés dans le tampon jusqu'à ce jour. Encore après "milisonds" le fil 2 doit faire une pause & attendre pour "X" ms.

Comment y parvenir. Ici le 1er thread est celui par défaut dans lequel mon code de bibliothèque serait en cours d'exécution. Comment puis-je y parvenir en utilisant C++?

+6

C'est une question très large et communément appelé le problème des producteurs et consommateurs. – OutOfBound

+0

Il n'est pas clair si le thread 1 peut également lire dans la structure de données. C++ 11 a les mutex nécessaires et 'std :: lock_guard' pour utiliser les mutex facilement. Vous auriez aussi besoin d'une minuterie, ou faites simplement dormir le fil. – Bernard

Répondre

0

En ce qui concerne la réponse générale à votre question générale, il y a deux options possibles:

1- utiliser une attente, le signal des commandes pour dormir et se réveiller threads en parallèle

2- utiliser un certain sommeil pour fournir X millisecondes en fil de lecture

Si vous avez besoin meilleure réponse, donner plus de détails

+0

a modifié la question avec plus de détails. – codeLover

0

vous pouvez utiliser std::mutex et std::condition_variable> à votre avantage. Et un double tampon garderait le verrouillage au minimum.

std::condition_variable> est la chose la plus proche d'un événement que la std a à offrir, son utilisation est un peu artificielle, mais cela fonctionne.

L'exemple ci-dessous utilise un double tampon afin que vous puissiez continuer à mettre en mémoire tampon des données pendant que le thread 2 enregistre dans un fichier, sans verrouillage. La variable std: condition_variable est utilisée pour que votre application puisse quitter sans attendre. Ceci est seulement nécessaire si vous voulez que votre application se termine rapidement, sinon vous pouvez utiliser une minuterie. L'appel à notify_all() empêchera wait_for() d'expirer, et réveillera le thread d'écriture immédiatement, afin qu'il puisse quitter sans attendre le délai d'attente. Voir ref à: http://en.cppreference.com/w/cpp/thread/condition_variable

tête:

#include <mutex> 

// a generic double buffer 
template<typename _Data> 
class DoubleBuffer 
{ 
private: 
    std::mutex mutex_; 

    std::vector<std::vector<_Data>> storeBuffer_; 
    std::vector<std::vector<_Data>> saveBuffer_; 

public: 
    void lock() { mutex_.lock(); } 
    void unlock() { mutex_.unlock();} 

    auto& GetStoreBuffer() { return storeBuffer_; } 
    auto& GetSaveBuffer() { return saveBuffer_; } 
    auto& Swap() 
    { 
    std::lock_guard<std::mutex> lock(mutex_); 
    std::swap(storeBuffer_, saveBuffer_); 
    } 
}; 

Dans votre bibliothèque:

#include <condition_variable> 
#include <thread> 
#include <chrono> 
#include <mutex> 
#include <vector> 
#include <string> 

// As an example, could be inside a class, or struct 
static std::condition_variable exiting; 
static std::mutex lk_exiting; 

static DoubleBuffer<std::string> yourBuffer; 

void FillLibraryDataStructure(std::vector<std::string> strings) 
{ 
    // the lock is only for the duration of a swap - very short at worst. 
    std::lock_guard<DoubleBuffer<std::string>> lock(yourBuffer); 
    yourBuffer.GetStoreBuffer().emplace_back(strings); 
} 

void StoreLoop() 
{ 
    for(;;) 
    { 
     { // wait_for() unlocks lk_exiting, doc says lock should 
      // be set before cv is triggered. 
      std::unique_lock<std::mutex> lk_exiting; 
      if (std::cv_status::no_timeout == exiting.wait_for(lk_exiting, 60s)) 
       break; // app is exiting 
     } 

     yourBuffer.Swap(); 

     auto& stringsToSave = GetSaveBuffer(); 
     // save... You do have plenty of time. 
    } 
} 

// as an example. A destructor would be a good place for this 
void Exit_Application() 
{ 
    // stops the wait_for operation in StoreLoop() 
    exiting.notify_all(); 
} 
+0

Merci. L'exemple de code n'est pas très clair quant à pourquoi utilisons-nous 2 buffers savebuffer et storebuffer alors pourquoi swapping. Comment la condition est-elle variable et muette? Demande de bien vouloir expliquer. – codeLover

+0

Dans le code que vous avez donné dans FillLibraryDataStructure() - je vois que vous passez DoubleBuffer en tant qu'argument au type de template lock_guard alors que lock_guard ne peut accepter que std :: mutex. Corrigez-moi si j'ai tort, s'il-vous plait. – codeLover