使用pthread时,我可以在创建线程时传递数据。
将新数据传递给已经运行的线程的正确方法是什么?
我正在考虑制作一个全局变量并从中读取我的线程。
由于
答案 0 :(得分:6)
这肯定有用。基本上,线程只是共享相同内存空间的轻量级进程。每个线程都可以使用位于该内存空间中的全局变量。
诀窍不是读者和作家一样。如果你有一个简单的全局内存块,比如int
,那么分配给int
可能是安全的。 Bt认为有点复杂,比如struct
。只是要明确,让我们说我们有
struct S { int a; float b; } s1, s2;
现在s1,s2
是struct 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
内部数据结构时可能会崩溃。)
典型的方法是让您的线程创建例程基本上是一个事件循环。您可以构建队列结构并将其作为参数传递给线程创建例程。然后其他线程可以排队,线程的事件循环将使它出列并处理数据。请注意,这比全局变量(或全局队列)更干净,因为它可以扩展为具有多个这些队列。
您需要在该队列数据结构上进行一些同步。可以编写整本书来介绍如何实现队列结构的同步,但最简单的事情就是有一个锁和一个信号量。修改队列时,线程会锁定。当等待某些东西出队时,消费者线程会等待一个由入队者递增的信号量。实现一些关闭消费者线程的机制也是一个好主意。