编写C API的线程安全C++包装器的努力

Effort to write a thread-safe C++ wrapper of C API

本文关键字:包装 努力 C++ 线程 API 编写 安全      更新时间:2023-10-16

我正在编写C API的‘threads-safe’C++包装,而API本身并不是内部线程安全的。我试过使用RAII。

我想知道,我的实现是否正确?以及它是否是线程安全的。我感谢对我的代码的任何评论。提前感谢!

要包装的C API如下,

 /* 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);

我的包装器实现如下:

    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;
}

谢谢!

我认为您需要像这样更改实现:

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;
} ;

这允许你写这样的代码:

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

所以用同一个对象生成多个日志;否则,第一个调用将关闭记录器,并且该对象是无用的。这是你想要的吗?

然后是第二个问题:你所说的线程安全是什么意思?是否要从不同的线程对同一对象进行日志记录?

然后,您可以在日志函数中添加一个互斥和一个锁保护,如下所示:

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 ;
} ;

简短回答:不,不是。首先,我认为必须有free()而不是delete,因为它是cAPI。您所做的可以使您的资源无泄漏程序,但不能保证线程安全。RAII是为了避免资源泄漏。有一种简单但效率低的方法来包装API以确保线程安全,从而在RAII类中添加静态互斥对象。

#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;