我在使用pthreads的程序遇到一些问题,其中发生了偶然的崩溃,这可能与线程如何对数据进行操作有关
所以我对如何使用线程和内存布局进行编程有一些基本问题:
假设公共类函数对某些字符串执行某些操作,并将结果作为字符串返回。该函数的原型可能是这样的:
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]指针地址 到字符串在堆上的位置
堆:[some mem addr]内存 分配给初始字符串 可能会成长或缩小
为了使函数线程安全,使用以下互斥锁(在“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 result) { 的pthread_mutex_lock(安培; someclasslock);
//省略了对字符串的错误检查 result = 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");
}
很抱歉这么长的说明。但我希望问题和预期目的是明确的,如果不让我知道,我会详细说明。
祝你好运。 克里斯
答案 0 :(得分:1)
1 a / b:不,都不会发生。函数的参数及其返回值位于堆栈上,每个线程都有自己的堆栈。但是,其他事情肯定会出错:
我建议您为每个线程创建一个新的SomeClass对象。在这种情况下,这些对象的所有成员只能由一个线程访问,并且不需要通过锁保护。 缺点是,在启动新线程后,您无法再从主线程访问它们。如果需要,那么你必须用锁来保护它们(锁也是该类的成员)。
话虽如此,函数somefunc似乎根本不会影响对象的任何成员,因此不需要保护。想想线程之间共享的粒度,我认为保护锁应该在调用somefunc的函数中。
答案 1 :(得分:0)
一般建议:尽量减少可能发生对共享数据的访问的位置。共享数据是指任何线程都可以随时访问的数据。
有一些处理多线程编程的一般方法:
当然还有其他方式,但这两种方式最常用 - 至少是我(特别是第一种)。