多线程澄清

时间:2013-10-16 21:16:55

标签: c++ multithreading

我一直在努力学习如何多线程并提出以下理解。我想知道我是正确的还是远的,如果我以任何方式不正确,如果有人能给我建议。

要创建一个线程,首先需要使用诸如<thread>之类的库或任何替代方法(我使用boost的多线程库来获得跨平台功能)。之后,您可以通过将其声明为(std::thread

来创建线程
std::thread thread (foo);

现在,您可以使用thread.join()thread.detach()。前者将等到线程结束,然后继续;而后者将与你打算做的任何事情一起运行。

如果你想从同时访问的线程中保护某些东西,比如一个向量std::vector<double> data,你可以使用一个互斥锁。

Mutex将被声明为全局变量,以便它们可以访问线程函数(或者,如果您创建的是一个多线程的类,则可以将互斥体声明为该类的私有/公共变量)。之后,您可以使用互斥锁锁定和解锁线程。

让我们快速浏览一下这个伪代码示例:

std::mutex mtx;
std::vector<double> data;
void threadFunction(){
  // Do stuff
  // ...
  // Want to access a global variable
  mtx.lock();
  data.push_back(3.23);
  mtx.unlock();
  // Continue
}

在此代码中,当互斥锁锁定线程时,它只锁定它与mtx.unlock()之间的代码行。因此,其他线程仍然会以他们的快乐方式继续,直到他们尝试访问数据(注意,我们也可能通过其他线程中的互斥锁)。然后他们会停下来,等待使用数据,锁定它,push_back,解锁并继续。请查看here以获取有关互斥锁的详细说明。

这就是我对多线程的理解。那么,我是非常错误还是准确?

1 个答案:

答案 0 :(得分:1)

您的评论引用&#34;锁定整个帖子&#34;。你不能锁定一部分线程。

锁定互斥锁时,当前线程将获取互斥锁的所有权。从概念上讲,您可以将其视为线程将其标记放置在互斥锁上(将其threadid存储在互斥锁数据结构中)。如果出现任何其他线程并尝试获取相同的互斥锁实例,则会发现互斥锁已经声明了#34;由其他人等待,直到第一个线程释放互斥锁。当拥有的线程稍后释放互斥锁时,等待互斥锁的其中一个线程可以唤醒,为自己获取互斥锁,然后继续。

在您的代码示例中,一旦获取互斥锁,可能无法释放互斥锁。如果对data.push_back(xxx)的调用抛出异常(内存不足?),则执行将永远不会到达mtx.unlock(),并且互斥锁将永远保持锁定状态。尝试获取该互斥锁的所有后续线程都将进入永久等待状态。他们永远不会醒来因为拥有互斥锁的线程是吐司。

出于这个原因,获取和释放关键资源(如互斥锁)应该以保证它们将被释放的方式完成,而不管执行是如何离开当前范围的。在其他语言中,这意味着将mtx.unlock()放在try..finally块的finally部分中:

mtx.lock();
try
{
    // do stuff
}
finally
{
    mtx.unlock();
}

C ++没有尝试过最终的陈述。相反,C ++利用其语言规则自动处理本地定义的变量。您在局部变量中构造一个对象,该对象在其构造函数中获取一个互斥锁。当执行离开当前函数作用域时,C ++将确保处置该对象,并且该对象在处置时释放锁。这是其他人提到的RAII。 RAII只使用包含每个C ++函数体的现有隐式try..finally块。