与线程

时间:2016-05-16 05:50:22

标签: c multithreading global-variables

除了主执行之外,我正在使用两个线程( 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

实际上我正在使用这两种方式(主要是因为我需要一个早期的“工作程序版本”)。作为我所指的变量交换的一个例子:

  1. 我将“keepalive”变量定义为全局变量(当线程进入无限循环时共享它)。
  2. 我正在通过struct传递通信配置数据。
  3. 我正在通过全局数组(在无限循环中更新)将仪器数据检索到main。
  4. 我正在检索文件的句柄和与struct的通信(最后,关闭并正确释放所有内容)。
  5. 对于使用全局变量与使用原子变量结构的缺点,我将不胜感激。 (代码清洁度,速度,效率,CPU /内存使用情况......)。

    感谢。

2 个答案:

答案 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