【问题标题】:How to safely operate on parameters in threads, using C++ & Pthreads?如何使用 C++ 和 Pthreads 安全地操作线程中的参数?
【发布时间】:2010-06-09 18:03:20
【问题描述】:

我在使用 pthread 的程序时遇到了一些问题,有时会发生崩溃,这可能与线程如何处理数据有关

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

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

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] 指针地址 到字符串在堆上的位置

堆:[Some mem addr] 内存 分配给初始字符串 可能会增长或缩小

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

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 已经被设置在函数在堆栈上的两个引用指针中,调度程序会占用线程的处理时间并让一个新线程进入,这会覆盖引用指向函数的指针,然后再次被调度程序停止,让第一个线程重新进入?

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

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

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

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

最好的问候。 克里斯

【问题讨论】:

    标签: c++ memory locking mutex pthreads


    【解决方案1】:

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

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

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

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

    【讨论】:

    • 谢谢两位抽空回复。
    【解决方案2】:

    一般建议:尽量减少可能访问共享数据的地方。我所说的共享数据是指任何线程随时都可以访问的数据。

    有一些处理多线程编程的一般方法:

    Producer consumer

    Reader writers

    当然还有其他方法,但是这两种是最常用的——至少对我来说是这样(尤其是第一种)。

    【讨论】:

      猜你喜欢
      • 2021-07-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-06-14
      • 2014-01-07
      • 2021-08-16
      • 1970-01-01
      • 2023-04-10
      相关资源
      最近更新 更多