2016-04-04 7 views
3

Ich schreibe einen 'threadsicheren' C++ - Wrapper der C-API, während die API selbst NICHT Thread-sicher ist. Ich habe versucht, RAII zu verwenden.Aufwand zum Schreiben eines threadsicheren C++ - Wrappers von C API

Ich würde gerne wissen, ist meine Implementierung korrekt? und ob es threadsicher ist. Ich freue mich über Kommentare zu meinem Code. Danke im Voraus!

Die C-API eingewickelt werden soll, wie folgt,

/* an data structure which represents a connection proxy to the logger: */ 
struct cLog_Logger; 

/* connect the logger, and returns a handle to it: */ 
cLog_Logger* cLog_connect(); 

/* appends a zero terminated string to the log: */ 
void cLog_write(cLog_Logger* logger, const char* message); 

/* closes the connection with the logger: */ 
void cLog_close(cLog_Logger* logger); 

Meine Implementierung der Umhüllung ist wie folgt:

class LoggerWrapper{ 

    public: 
     LoggerWrapper(){    //constructor 
      cLog= cLog_connect(); 
     } 

     void log(const std::string &message){ //entry point 
      cLog_write(cLog, message); 
      cLog_close(cLog); 
      } 

     ~LoggerWrapper(){  //destructor 
      delete cLog; 
     } 
    protected: 
     cLog_Logger *cLog; 
} 

Dank!

+0

Wo sind die Gewinde? – Ajay

+0

@Ajay, Threads sind überall außerhalb Wrapper :) – user2807083

Antwort

3

Ich glaube, Sie brauchen die Umsetzung wie folgt zu ändern:

Sie
class LoggerWrapper{ 

public: 
    LoggerWrapper(){    //constructor 
     cLog= cLog_connect(); 
    } 

    void log(const std::string &message){ //entry point 
     cLog_write(cLog, message); 
     } 

    ~LoggerWrapper(){  //destructor 
     cLog_close(cLog); 
     delete cLog; 
    } 
protected: 
    cLog_Logger *cLog; 
} ; 

Dies ermöglicht Code wie folgt zu schreiben:

LoggerWrapper logger ; 
logger.log("Something") ; 
logger.log("Something else) ; 

so mehr als ein Protokoll mit dem gleichen Objekt machen; andernfalls schließt der erste Aufruf den Logger und das Objekt ist nutzlos. Ist das was du willst?

Dann gibt es die zweite Frage: Was meinst du mit Thread-Sicherheit? Möchten Sie dasselbe Objekt aus verschiedenen Threads protokollieren?

Dann können Sie einen Mutex und eine Sperre Wache innerhalb Log-Funktion wie folgt hinzu:

class LoggerWrapper{ 

public: 
    LoggerWrapper(){    //constructor 
     cLog= cLog_connect(); 
    } 

    void log(const std::string &message){ //entry point 
     std::lock_guard<std::mutex> guard(mutex); 
     cLog_write(cLog, message); 
     } 

    ~LoggerWrapper(){  //destructor 
     cLog_close(cLog); 
     delete cLog; 
    } 
protected: 
    cLog_Logger *cLog; 
    std::mutex mutex ; 
} ; 
+0

Ich glaube nicht, dass der Mutex als nicht-statische Klasse Mitglied Problem lösen wird. Stellen Sie sich vor, Sie erstellen 2 LoggerWrapper-Instanzen in 2 verschiedenen Threads. Boom! – user2807083

+0

@marom, es ist ein guter Punkt, um 'cLog_close (cLog)' in den Destruktor zu verschieben, meine Überlegung war es, die Verbindung zu schließen, sobald das Protokollschreiben fertig ist, obwohl ich nicht sicher bin, ob es Sinn macht. – ulyssis2

+0

@Marom, Ihre Spekulation auf "Thread-Sicherheit" ist richtig, die API hat keinen Mechanismus, um Synchronisationsprobleme zu vermeiden. Ihre Lösung scheint richtig zu sein, vielen Dank! – ulyssis2

2

Kurze Antwort: nein, es ist nicht. Zuerst denke ich, dass es free() anstelle von delete geben muss, weil es c api ist. Was Sie tun können, geben Sie Ihre Ressource-leckfreie Programm, aber nicht Thread-sicher. RAII dient zur Vermeidung von Ressourcenlecks. Es gibt eine einfache, aber ineffiziente Möglichkeit, Ihre API für threadsichere Methoden zum Hinzufügen statischer Mutexe in Ihrer RAII-Klasse zu verwenden.

#include <mutex> 

class LoggerWrapper{ 

public: 
    LoggerWrapper() : l(globalLock); 
    {    //constructor 
     cLog= cLog_connect(); 
    } 

    void log(const std::string &message){ //entry point 
     cLog_write(cLog, message); 
     cLog_close(cLog); 
     } 

    ~LoggerWrapper(){  //destructor 
     free(cLog); // I think here must be free(), but not sure 
    } 
protected: 
    cLog_Logger *cLog; 
    static std::mutex globalLock; 
    std::lock_guard<std::mutex> l; 
} 

std::mutex LoggerWrapper::globalLock; 
+0

danke! Da wir die C++ - Wrapper-Klasse diskutieren, denke ich, dass ree() und delete keine signifikanten Unterschiede darstellen. – ulyssis2

+0

Könnten Sie bitte die Verwendung des lock_guard-Mitglieds erklären? das Mitglied 'l' wird bei der Initialisierung zugewiesen, tut aber später nichts. – ulyssis2

+0

@ ulyssis2, lock_guard ist eine RAII-Vorlage, die die Mutex-Sperre im Konstruktor übernimmt und die Mutex-Sperre in ihrem Destruktor freigibt. Solange lock_guard existiert, hält es Mutex im gesperrten Zustand. – user2807083

Verwandte Themen