除了主执行之外,我正在使用两个线程( pthread_t )的mingw程序。每个线程包含一个无限循环,用于与外部仪器进行连续通信,每个通信具有不同的速度和协议。主程序只是在用户请求时在运行时显示仪器数据。只有当main中的“keepalive”变量设置为0时,线程中的无限循环才会退出。 为了在线程之间交换数据,我想知道我所知道的两种方式的优缺点:
将参数传递给线程(可以使用pthread_create的最后一个参数传递结构: * arg )。
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg);
使用全局变量并控制并发性( pthread_mutex_lock 和 pthread_mutex_unlock )
实际上我正在使用这两种方式(主要是因为我需要一个早期的“工作程序版本”)。作为我所指的变量交换的一个例子:
对于使用全局变量与使用原子变量结构的缺点,我将不胜感激。 (代码清洁度,速度,效率,CPU /内存使用情况......)。
感谢。
答案 0 :(得分:3)
几乎普遍认为你不应该使用全局变量。(我想你可能也不理解what extern
is for。)
然后......
[..]因为我关注速度和效率。
您正在利用锁定来同步访问权限。因此,忘掉它,由此引起的开销将影响其他任何东西。由于(链接时间)已知地址,使用全局潜在可能会“更快”。不过,我严重怀疑这是否有任何意义。 如果不咨询分析器,请不要过早优化。
全局变量的缺点是在线程之间测试通信变得更加困难。传递struct
时,您可以轻松启动另一个线程,并让该线程与您要测试其通信的端点进行通信。您无需更改任何一个端点,只需更改这些线程的启动方式。
此外,由于类似的原因,不容易扩展您的应用程序。假设您有两个线程,例如“搜索者”(用于搜索某些数据)和“索引器”(负责存储匹配,并可能分离进一步的操作)。如果他们通过全局变量进行通信,您将如何添加另一个搜索器线程?你必须使用另一个全局来进行新搜索器和索引器之间的通信,复制大部分搜索器线程(所有改变的是用于通信的变量)。与传递包含“通信通道”的结构相比:在这里,您甚至不需要触摸搜索器代码,只需启动另一个。 (必须更改索引器,以便在两个示例中都能有多个输入源。)
最后,通过线程启动上的结构传递“通信通道”,可以隐藏通信通道,从而限制哪些线程可以访问它。在尝试确定谁从频道写入/读取时,这非常有价值。 (“那是什么线程写的那个sh#t?”)
答案 1 :(得分:0)
如果可以,请尽量避免使用全局变量,因为它们可能会导致并发问题,并使您的代码可读性降低。我建议创建一个包含原子类型变量的userdata结构。像这样:
struct user_data {
atomic_bool myBool;
atomic_int myInt;
};
int main() {
pthread_t myThread;
struct user_data userdata = {
.myBool = &ATOMIC_VAR_INIT(false),
.myInt = &ATOMIC_VAR_INIT(0)
};
if (pthread_create(&myThread, NULL, myFunction, &userdata) {
// error handling
}
}
这将避免并发问题并使您的代码更具可读性。 要修改原子变量,请使用原子操作,例如:
atomic_store
atomic_load
atomic_fetch_add
这是原子操作库的reference。