在C++中使用openmp进行多线程编程

2023-10-26

声明:本文是基于Joel Yliluoma写的Guid into OpenMP:Easy multithreading programming for C++而写的,基本是按照自己的理解,用自己语言组织的。其中大部分例子依然用原来文章的例子,本文仅作为学习笔记之用。

前言

多线程在实际的编程中的重要性不言而喻。对于C++而言,当我们需要使用多线程时,可以使用boost::thread库或者自从C++ 11开始支持的std::thread,也可以使用操作系统相关的线程API,如在Linux上,可以使用pthread库。除此之外,还可以使用omp来使用多线程。它的好处是跨平台,使用简单。
在Linux平台上,如果需要使用omp,只需在编译时使用"-fopenmp"指令。在Windows的visual studio开发环境中,开启omp支持的步骤为“项目属性 -> C/C++ -> 所有选项 -> openmp支持 -> 是(/openmp)”。
本文我们就介绍omp在C++中的使用方法。

c++ openmp入门简介

openmp是由一系列#paragma指令组成,这些指令控制如何多线程的执行程序。另外,即使编译器不支持omp,程序也也能够正常运行,只是程序不会多线程并行运行。以下为使用omp的简单的例子:
int main()
{
	vector<int> vecInt(100);
        #pragma omp parallel for
	for (int i = 0; i < vecInt.size(); ++i)
	{
	    vecInt[i] = i*i;
	}
	return 0;
}

以上代码会自动以多线程的方式运行for循环中的内容。如果你删除"#pragma omp parallel for"这行,程序依然能够正常运行,唯一的区别在于程序是在单线程中执行。由于C和C++的标准规定,当编译器遇到无法识别的"#pragma"指令时,编译器自动忽略这条指令。所以即使编译器不支持omp,也不会影响程序的编译和运行。

omp语法

所有的omp指令都是以"#pragma omp“开头,换行符结束。并且除了barrier和flush两个指令不作用于代码以外,其他的指令都只与指令后面的那段代码相关,比如上面例子中的for循环。

parallel编译指示

parallel告诉编译器开始 一个并行块,编译器会创建一个包含N(在运行时决定,通常为硬件线程数)个线程的线程组,所有线程都运行接下来的语句或者由”{...}"包含的代码块,在这执行结束之后,又回到主线程,创建的这N个线程会被回收。
#pragma omp parallel
{
    cout << "parallel run!!!\n";
}

以上代码在4双核4线程的cpu的电脑上运行时,输出了4行”parallel run!!!"。即编译器创建了一个包含4个线程的线程组来运行这段代码。在这段代码运行结束后,程序执行回到主线程。GCC编译器的实现方式是在内部创建一个函数,然后将相关的执行代码移至这个函数,这样一来代码块中定义的变量成为了线程的局部变量,互不影响。而ICC的实现方式是利用fork()来实现。

线程之间共享的变量是通过传递引用或者利用register变量来实现同步的,其中register变量在代码执行结束之后或者在flush指令调用时进行同步。

我们也可以利用if条件判断来决定是否对后续的代码采用并行方式执行,如:

externint parallelism_enabled;
#pragma omp parallel for if(parallelism_enabled)
for(int c=0; c<n;++c)
    handle(c);

在这个例子中,如果parallelism_enabled为false,那么这个for循环只会由一个线程来执行。

for指令

omp中的for指令用于告诉编译器,拆分接下来的for循环,并分别在不同的线程中运行不同的部分。如果for指令后没有紧接着for循环,编译器会报错。例如,
#pragma omp parallel  for
for (int i = 0; i < 10; ++i)
{
   printf("%d ", i);
}

 
   
以上的代码执行后,会打印出[0,9]这10个数字。但是它们的顺序是随机出现的,在我的电脑上,运行的输出是"0 1 2 8 9 6 7 3 4 5"。事实上,输出结果不会是完全随机的,输出的序列是局部有序的,因为在编译器对for循环的拆分相当于下面的代码:

                
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在C++中使用openmp进行多线程编程 的相关文章

  • 自动映射器多对一映射

    我想将一种类型映射到另一种类型 但我在第一种类型中有多个属性 需要获取其他类型的一个属性 例如 public class A public int a get set public int b get set public int c ge
  • JQuery、ASCX 和 webmethods 似乎不起作用

    我有一个级联下拉列表 其中 3 个 类型 类别和子类别 首先类型负载 然后选择类型 类别负载以及选择类别 子类别负载 我还有 2 个按钮 添加类别 和 添加子类别 单击这些按钮后 我调用 JQuery 模态表单来添加它们 我在代码后面使用
  • 如何在 ASP.Net Core 6 Web Api 中依赖注入 Microsoft Graph 客户端

    我正在尝试使用 ASP Net Core 6 设置 Web api 以便用户可以到达我的端点 然后我使用特权帐户在 Teams 中执行一些工作 我认为我没有正确连接 DI 部分 因为在向 Teams 发出请求时出现以下错误 MsalUiRe
  • 在 TPL Dataflow 中,是否可以在创建块之后但使用之前更改 DataflowBlockOptions?

    有效果吗 我想推迟设置 ExecutionDataflowBlockOptions SingleProducerConstrained 属性 直到我准备好将网络链接在一起 因为 我想将创建块及其语义与将网络及其语义链接在一起分开 但据我所知
  • 忽略父进程中的信号

    我正在尝试实现一个 shell 程序 我希望 shell 程序忽略 SIG INT ctrl c 但在我的程序中 子进程也会忽略 SIG INT 信号 但它不应该这样做 因为 exec 应该将子进程带到另一个程序 并且该程序默认情况下应该处
  • 不要覆盖 Azure Blob 存储

    我有一种将文件添加到 Azure Blob 存储的方法 问题是我试图指定一个条件 在该条件下它不会覆盖 blob 而只是添加到其中 我正在尝试使用参数访问条件 但是 VS 说这个方法不能采用两个参数 async void archiveNe
  • 从 C# 访问 COM vtable

    C 中有没有办法访问 COM 对象的虚拟方法表以获取函数的地址 经过大量搜索和拼凑不同的部分解决方案后 我弄清楚了如何做到这一点 首先 您需要为您尝试访问的对象定义 COM 组件类 ComImport Guid InterfaceType
  • ICSharpCode.Decompiler + Mono.Cecil -> 如何为单个方法生成代码?

    我可以使用 Mono Cecil 和 ICSharpCode Decompiler 生成类型或程序集的代码 但是 如果我尝试为单个方法生成代码 我将收到错误 对象引用未设置为对象的实例 你们能给我任何关于这个的提示吗 提前感谢您的所有帮助
  • 使用 C# 启动 Outlook

    我可以让 C 在代码中启动 Outlook 吗 在 VB6 中 我们使用对象 Outlook Application 并编写 Set oOutlook CreateObject Outlook Application Set oNameSp
  • 如何转换 UTF-8 <-> UTF16 可移植

    有没有一种简单 可移植的方法 至少是 win32 linux 将 UTF 16 转换为 UTF 8 并返回 最好使用升压 谢谢你的帮助 托比亚斯 Both libiconv http www gnu org software libicon
  • 有没有一种方法可以在 TreeView.Nodes 集合中搜索 TreeNode.Text 字段?

    像这样 TreeNode treeNodes treeView Nodes Find searchString true 但我希望它在text字段而不是name field 我不知道有任何内置方法 但你可以使用 LINQ TreeNode
  • 如何检查我的程序是否有数据通过管道传输到其中

    我正在编写一个应该通过标准输入读取输入的程序 所以我有以下结构 FILE fp stdin 但是 如果用户没有将任何内容通过管道传输到程序中 这就会挂起 我如何检查用户是否确实将数据通过管道传输到我的程序中 例如 gunzip c file
  • 更改为通用接口对性能的影响

    我使用 Visual Studio 使用 C NET 开发应用程序 ReSharper 在我的方法原型中经常建议我用更通用的类型替换输入参数的类型 例如 如果我仅在方法主体中使用带有 foreach 的列表 则使用 List 和 IEnum
  • 如何获取 EF 中的实体更改增量?

    我只需要获取已更改字段的列表 数据存储区是 ssce 因此没有可用的触发器 EF 是否支持获取列表或构建通用组件 根据上下文的类型和生成的实体 您可以通过多种不同的方式来完成此操作 如果对象继承自 Entity 或 POCO 您可以使用Ob
  • 是否有普遍接受的 GMP 替代方案来实现任意精度? [关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 在寻找 BigInt 库的过程中 我发现了这篇文章 Microsoft Windows 上的 C 或
  • 如何使用 C# 以编程方式识别对方法的引用数量

    我最近继承了需要一些修剪和清理的 C 控制台应用程序 长话短说 该应用程序由一个包含超过 110 000 行代码的类组成 是的 单个类中有超过 110 000 行 当然 该应用程序是我们业务的核心 全天候运行更新动态网站上使用的数据 尽管我
  • 使用 System.Windows.Forms.Timer.Start()/Stop() 与 Enabled = true/false

    假设我们在 Net 应用程序中使用 System Windows Forms Timer 在计时器上使用 Start 和 Stop 方法与使用 Enabled 属性之间有什么有意义的区别吗 例如 如果我们希望在进行某些处理时暂停计时器 我们
  • 以编程方式将 UserControl 从 ContentControl 移动到另一个 ContentControl

    在 WPF 应用程序中 我想在代码中将 UserControl 从 ContentControl 移动到另一个控件 myContentControl2 Content myUserControl 在这种情况下我得到一个错误 指定的元素已经是
  • 如何在不加载到内存的情况下对大型 csv 文件进行排序

    我有 20GB csv 文件 如下所示 CallId MessageNo Information Number 1000 1 a 2 99 2 bs 3 1000 3 g 4 66 2 a 3 20 16 3 b 1000 7 c 4 99
  • WPF - 将窗口置于前面

    我有一个 WPF 窗口 我没有关闭它 相反 我执行 Hide 和 Show 它 现在 当我双击记录上网格中的主窗口时 这将触发 Show 窗口 该窗口将始终显示在主窗口后面 我尝试过以下方法 但没有成功 view Show view Act

随机推荐