我在使用 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;
}
- 假设字符串是动态的,存储在堆上,但对字符串的引用在运行时分配在堆栈上是否正确?
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;
}
这是一种锁定正在对字符串(所有三个)执行的操作的安全方法吗,或者在以下情况下调度程序是否可以停止线程,我认为这会打乱预期逻辑:
一个。调用函数后,参数:strOne 和 strTwo 已设置在函数在堆栈上的两个引用指针中,调度程序会带走线程的处理时间并让新线程进入,这会覆盖引用指向函数的指针,然后调度程序再次停止该函数,让第一个线程返回?
“result”字符串是否也会发生同样的情况:第一个字符串构建结果,解锁互斥锁,但在返回之前,调度程序让另一个线程执行所有工作,覆盖结果等。
或者当另一个线程正在执行它的任务时,引用参数/结果字符串是否被压入堆栈?
在线程中执行此操作并“返回”结果的安全/正确方法是传递对将用结果填充的字符串的引用:
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/