多线程和单线程代码维护

Posted

技术标签:

【中文标题】多线程和单线程代码维护【英文标题】:Multithreaded and singlethreaded code maintenance 【发布时间】:2019-06-11 08:43:03 【问题描述】:

我有一个应用程序,我想使用多线程(通过 OpenMP)或单线程运行。

我有一个#define MT true //if true, then multithreaded, else singlethreaded 宏,它可以在两个选项之间切换。

假设在我的单线程应用程序中,有一个数组:

int foo [5];

在多线程的情况下,(假设有 4 个线程),我不得不将上面的声明为:

int foo[4][5];

单线程情况下的函数,其声明为:

void work_on_foo(int* foo)
    foo[4] = 2;

变成

void work_on_foo(int thread, int** foo)
    foo[thread][4] = 2;

目前,为了处理这个代码膨胀,我正在做如下粗暴的复制:

#if MT
    void work_on_foo(int thread, int** foo)
#else
    void work_on_foo(int* foo)
#endif
#if MT
        foo[thread][4] = 2;
#else
        foo[4] = 2;
#endif

这当然很难看。有没有办法防止这种蛮力的代码维护方式?唯一的另一种方法似乎是拥有两个独立的代码库,我想避免这样做。

【问题讨论】:

在这种情况下,我使用不同的头文件来分隔代码,但仍然能够保留共享代码,然后使用配置文件生成正确的代码。 根据您的描述,在构建程序时(最大)线程数是已知的。在这种情况下,我会简单地将单线程情况视为线程数为 1 的特殊情况。交换采用thread 参数的函数的参数,使其最后一个,并为该参数提供1 的默认值。最多,您的函数只需在继续之前检查接收到的thread 值的有效性 - 无需担心实现多线程和单线程版本。 代码写错了。在编写良好的代码中,“业务逻辑”部分不应该知道它是否是多线程。如果您的主逻辑代码具有参数int thread,那么您无论如何都会被搞砸。 IMO 问题被错误地询问,这符合XY problem。 @Tryer - 如果其中一个维度设置为 1,那么数组(可能是最大的存储用户)如何“浪费空间”????数组int x[1][4] 消耗的内存与数组int x[4] 消耗的内存相同。唯一的区别是元素的索引方式(以及用于附加维度的变量,这通常是微不足道的)。除非您使用的硬件资源非常有限(如果您使用的是 OpenMP,则几乎可以肯定不会)差异将是微不足道的。阅读“过早优化”。/ 如果数组的索引为thread 的元素只被给定索引的线程使用,那么你就有一个线程本地数据。 OpenMP 对此类数据有一个明确定义的概念:被声明为static int foo [5];,数组通过使用#pragma omp threadprivate(foo) 变为线程局部的。在本文中查看更多信息:pages.tacc.utexas.edu/~eijkhout/pcse/html/omp-data.html。 【参考方案1】:

类来处理它们怎么样? 创建具有所需接口的基类并派生两个类,一个用于单线程,一个用于多线程。如果你要改变你只需要改变你的工厂。 (看看dependency injection)

【讨论】:

让我看看。但在我看来,我仍然需要重新实现它两次——一次用于单线程,一次用于多线程。 嗯,你已经这样做了。通过使用类,您只是按类分隔它们,而不是使用#define。如果你用不同的参数调用它们,我认为你不能避免使用两个不同的函数

以上是关于多线程和单线程代码维护的主要内容,如果未能解决你的问题,请参考以下文章

简单多线程和单例学习例一

C++最佳实践 | 4. 可维护性

C++最佳实践 | 4. 可维护性

C++最佳实践 | 5. 可移植性及多线程

C++最佳实践 | 5. 可移植性及多线程

为什么Redis要用单线程