c++ - 如何使用 C++ 和 Pthreads 安全地操作线程中的参数?

标签 c++ memory locking mutex pthreads

我在使用 pthreads 的程序上遇到了一些问题,偶尔会发生崩溃,这可能与线程对数据的操作方式有关

所以我有一些关于如何使用线程和内存布局进行编程的基本问题:

假设一个公共(public)类函数对一些字符串执行一些操作,并将结果作为字符串返回。函数的原型(prototype)可能是这样的:

std::string SomeClass::somefunc(const std::string &strOne, const std::string &strTwo)
{
 //Error checking of strings have been omitted
 std::string result = strOne.substr(0,5) + strTwo.substr(0,5);
 return result;
}
  1. 假设字符串是动态的,存储在堆上,但对字符串的引用在运行时分配在堆栈上是否正确?

Stack: [Some mem addr] pointer address to where the string is on the heap

Heap: [Some mem addr] memory allocated for the initial string which may grow or shrink

为了使函数线程安全,函数使用以下互斥锁(在“SomeClass”中声明为私有(private))锁定进行扩展:

std::string SomeClass::somefunc(const std::string &strOne, const std::string &strTwo)
{
 pthread_mutex_lock(&someclasslock);

 //Error checking of strings have been omitted
 std::string result = strOne.substr(0,5) + strTwo.substr(0,5);

 pthread_mutex_unlock(&someclasslock); 

 return result;
}
  1. 这是一种锁定正在对字符串(所有三个)执行的操作的安全方法吗,或者在以下情况下调度程序是否可以停止线程,我认为这会打乱预期逻辑:

    一个。调用函数后,参数:strOne 和 strTwo 已设置在函数在堆栈上的两个引用指针中,调度程序会带走线程的处理时间并让新线程进入,这会覆盖引用指向函数的指针,然后调度程序再次停止该函数,让第一个线程返回?

    “result”字符串是否也会发生同样的情况:第一个字符串构建结果,解锁互斥锁,但在返回之前,调度程序让另一个线程执行所有工作,覆盖结果等。

或者当另一个线程正在执行它的任务时,引用参数/结果字符串是否被压入堆栈?

  1. 在线程中执行此操作并“返回”结果的安全/正确方法是传递对将用结果填充的字符串的引用:

    void SomeClass::somefunc(const std::string &strOne, const std::string &strTwo, std::string 结果) { pthread_mutex_lock(&someclasslock);

    //省略了字符串的错误检查 结果 = strOne.substr(0,5) + strTwo.substr(0,5);

    pthread_mutex_unlock(&someclasslock);

本意逻辑是“SomeClass”类的几个对象创建新的线程,将自己的对象作为参数传递,然后调用函数:“someFunc”:

int SomeClass::startNewThread()
{

 pthread_attr_t attr;
 pthread_t pThreadID;

 if(pthread_attr_init(&attr) != 0)
  return -1;

 if(pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) != 0)
  return -2;

 if(pthread_create(&pThreadID, &attr, proxyThreadFunc, this) != 0)
  return -3;

 if(pthread_attr_destroy(&attr) != 0)
  return -4;

 return 0;
}

void* proxyThreadFunc(void* someClassObjPtr)
{
 return static_cast<SomeClass*> (someClassObjPtr)->somefunc("long string","long string");
}

抱歉,描述太长了。但我希望问题和预期目的是明确的,如果没有让我知道,我会详细说明。

最好的问候。 克里斯

最佳答案

1 a/b:不,两者都不可能发生。函数的参数及其返回值位于堆栈中,每个线程都有自己的堆栈。然而,其他事情肯定会出错:

  • 其中一个字符串操作可能会引发异常,从而阻止某些类锁被解锁,您的应用程序将挂起。
  • 假设传递给函数的字符串在线程之间共享(如果不是,则不需要锁),另一个线程可以在调用函数之后和获取锁之前调用它们的析构函数。在那种情况下,字符串操作会导致未定义的行为。

我建议您为每个线程创建一个新的 SomeClass 对象。在那种情况下,这些对象的所有成员只能由一个线程访问,不需要用锁保护。 缺点是在启动新线程后您无法再从主线程访问它们。如果那是必需的,那么您必须用锁来保护它们(锁也将是该类的成员)。

话虽如此,函数 somefunc 似乎根本不影响对象的任何成员,因此不需要保护。想想线程之间共享的粒度,在我看来保护锁应该在调用somefunc的函数中。

关于c++ - 如何使用 C++ 和 Pthreads 安全地操作线程中的参数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3008521/

相关文章:

c++ - 从 AudioInputIOProc 创建 CMSampleBufferRef

C内存映射

t-sql - 分离数据库/脱机失败

java - 使用 FileLock 将行追加到文件

c++ - CLion对C++概念的支持

c++ - 何时在 OpenGL 中执行 3D 碰撞检测?

c++ - OpenGL:gluUnProject 的结果不是预期的结果

android - 如何从android中的手机内存中读取文件?

c++ - 堆栈内存与堆内存

c# - 在两个不同的代码块使用相同的锁对象?