如何将数据传递给正在运行的线程

时间:2011-05-30 00:30:20

标签: c++ c multithreading pthreads

使用pthread时,我可以在创建线程时传递数据。

将新数据传递给已经运行的线程的正确方法是什么?

我正在考虑制作一个全局变量并从中读取我的线程。

由于

4 个答案:

答案 0 :(得分:6)

这肯定有用。基本上,线程只是共享相同内存空间的轻量级进程。每个线程都可以使用位于该内存空间中的全局变量。

诀窍不是读者和作家一样。如果你有一个简单的全局内存块,比如int,那么分配给int可能是安全的。 Bt认为有点复杂,比如struct。只是要明确,让我们说我们有

struct S { int a; float b; } s1, s2;

现在s1,s2struct S类型的变量。我们可以初始化它们

s1 = { 42,  3.14f };

我们可以分配它们

s2 = s1;

但是当我们分配它们时,处理器不能保证一步完成整个结构的赋值 - 我们说它不是 atomic 。现在让我们想象两个线程:

thread 1:
   while (true){
      printf("{%d,%f}\n", s2.a, s2.b );
      sleep(1);
   }

thread 2:
   while(true){
      sleep(1);
      s2 = s1;
      s1.a += 1;
      s1.b += 3.14f ;
   }

我们可以看到我们希望s2拥有值{42, 3.14}, {43, 6.28}, {44, 9.42} ....

但我们看到的印刷品可能与

类似
 {42,3.14}
 {43,3.14}
 {43,6.28}

 {43,3.14}
 {44,6.28}

等等。问题是线程1可以在该分配期间的任何时间获得控制并“查看”s2。

道德观点是,虽然全局记忆是一种完美可行的方法,但你需要考虑你的线程相互交叉的可能性。有几种解决方案,基本的是使用信号量。信号量有两个操作,混淆地将荷兰语命名为 P V

P 只需等待变量为0并继续,向变量加1; V从变量中减去1。唯一特别的是他们这样做原子地 - 他们不能被打断。

现在,您编码为

吗?
thread 1:
   while (true){
      P();
      printf("{%d,%f}\n", s2.a, s2.b );
      V();
      sleep(1);
   }

thread 2:
   while(true){
      sleep(1);
      P();
      s2 = s1;
      V();
      s1.a += 1;
      s1.b += 3.14f ;
   }

并保证在线程1尝试打印时,你永远不会让线程2完成一项任务。

(顺便说一句,Pthreads有信号量。)

答案 1 :(得分:3)

答案 2 :(得分:2)

全局变量开始时很糟糕,多线程编程更糟糕。相反,线程的创建者应该分配某种传递给pthread_create的上下文对象,其中包含向线程传递信息和从线程传递信息所需的缓冲区,锁,条件变量,队列等。

答案 3 :(得分:2)

您需要自己构建它。最典型的方法需要来自另一个线程的一些合作,因为它将是一个奇怪的接口来“中断”正在运行的线程,其中一些数据和代码要在其上执行...这也会有一些相同的棘手问题。像POSIX信号或IRQ这样的东西,如果你没有仔细考虑过,它们很容易在处理时自己拍脚...(简单的例子:你不能在信号内调用malloc处理程序,因为您可能在malloc的中间被中断,因此在访问仅部分更新的malloc内部数据结构时可能会崩溃。)

典型的方法是让您的线程创建例程基本上是一个事件循环。您可以构建队列结构并将其作为参数传递给线程创建例程。然后其他线程可以排队,线程的事件循环将使它出列并处理数据。请注意,这比全局变量(或全局队列)更干净,因为它可以扩展为具有多个这些队列。

您需要在该队列数据结构上进行一些同步。可以编写整本书来介绍如何实现队列结构的同步,但最简单的事情就是有一个锁和一个信号量。修改队列时,线程会锁定。当等待某些东西出队时,消费者线程会等待一个由入队者递增的信号量。实现一些关闭消费者线程的机制也是一个好主意。