C++ 成员函数线程安全

c++ member function thread safe

本文关键字:安全 线程 函数 成员 C++      更新时间:2023-10-16

我正在编写一个用于记录消息的函数。我将从不同的线程调用此打印函数。我的代码如下:

MyLog::printLog(const char* s)
    {
            std::string myline(s);
            //m_Mutex is class member and there will be only object for this class
            // shared by all threads
            int ret = pthread_mutex_lock(&m_Mutex);
            if ( ret != 0 )
            {
                    std::cout<<" trying to lock same mutex char* "<<std::endl;
            }

            //code to log message in File
            pthread_mutex_unlock(&m_Mutex);
     }

我的问题是,上面的函数是否从不同的线程调用,参数如"来自线程 1"、"来自线程 2",...是否有可能 const char *s 会乱七八糟地打印错误的值。?我希望我的问题很清楚.

你的函数将按预期工作,因为myline是一个局部变量(每个线程都有自己的堆栈,所以有自己的myline实例(

如果你从不同的线程调用这个函数,并且你对参数所做的任何更改const char* s都受到互斥锁m_Mutex的保护,那么你会很好,不会有任何混乱。

编辑

实际上,当从不同的线程调用时,对这个函数的每次调用都会有自己的堆栈,并且看到它const char*你不能改变你的参数,所以没有必要用互斥锁来保护它。

您的变量s是调用它的线程的本地变量,并且const

然后复制到局部变量 myline 绝对不会弄乱任何东西,因为每个线程都有它的调用堆栈,当调用此函数时,该堆栈上存在一个myline实例,该实例完全独立且独立于任何其他线程。

这取决于

您如何调用printLog函数。如果传递给函数的地址的字符串被不同的线程改变,那么您可能无法在日志函数中看到它的一致视图。如果您传入指向不可变字符串的指针,例如文字,那么您没问题。

下面是一个不错的示例:

void from_thread_one()
{
    MyLog::printLog("Hello World");  // immutable string
}
void from_thread_two()
{
    MyLog::printLog("Another text");  // ditto
}

另一方面,这里有一个不行的例子,有一个种族:

char globalString[] = "This is a really long string";
void from_thread_one()
{
    globalString[5] = 'A';
    MyLog::printLog(globalString);
}
void from_thread_two()
{
    globalString[8] = 'Q';
    MyLog::printLog(globalString);
}

在此设置中,您正在创建字符串的副本(通过 std::string myline(s); (,而 s 指向的数组的内容可以在另一个线程中同时更改。在这种情况下,取消引用字符指针也必须在关键部分内进行。

设置的根本问题是原始字符指针没有隐式语义来告诉用户哪些行为是可接受的,哪些是不可接受的。如果按值传递实际std::string,则可以消除从printLog函数同步对字符串的访问的不确定性,并将责任完全转移到调用方中。