C/C++函数的本质以及多线程函数的调用过程

2023-10-29

C/C++中,函数的本质是一段可执行代码,代码包括了局部变量、全局变量的地址等等。到汇编语言的级别,变量函数等都可以视为汇编的代码片段。函数的本质就是一个可执行代码片段的集合

线程的详细介绍:http://www.cnblogs.com/tracylee/archive/2012/10/29/2744228.html
一个线程有自己的空间,有自己的局部变量。当一个线程执行一个函数的时候,会复制函数的代码段到自己的线程空间,之后执行该代码段。对于局部变量,每个线程会保存一个局部变量的副本,因为局部变量是保存在栈内存,所以一个线程更改局部变量不会影响其他线程的局部变量。全局变量是保存在堆内存上的,因此可以理解为线程是直接操作堆内存上的全局变量,因此如果一个线程改了全局变量,那么其他线程对应的全局变量肯定会更改,因为堆内存只有一个。

在多线程编程的过程中,所谓的添加互斥量、锁和条件变量等,本质上是为了保护堆内存上的东西,或者说是全局变量。所谓的竞争条件也是指的全局的,函数内部的局部的东西,不会引起竞争!!!!!

可以这么认为,对于C++11中的std:thread来说,函数是其执行的基本单位,这里说的函数包括普通函数、函数对象、std::funtion、仿函数、lambda表达式等。执行的时候,线程会复制函数的代码片段到自己的线程空间中去执行。线程空间的本身是封闭的,也就是说一个同级别的线程不能更改另一个线程的代码片段。。我们说的线程之间的通信,本质上说的是通过全局变量的状态,使得不同线程之间可以相互通信!!!

对于类的成员函数来说,线程复制函数的时候,类的成员变量相对于线程来说也是全局!!!!

#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <chrono>

static int N = 0;

void fun(int n) {
  int t = 0;
  for (int i = 0; i < n; ++i) {
    ++t;
    ++N;
  }
  std::this_thread::sleep_for(std::chrono::milliseconds(100));
  std::cout << "local: " << t << std::endl;
  std::cout << "global: " << N << std::endl;
}

class C {
public:
  void fun(int n) {
    int t = 0;
    for (int i = 0; i < n; ++i) {
      ++t;
      ++_N;
    }
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
    std::cout << "local: " << t << std::endl;
    std::cout << "global: " << _N << std::endl;
  }

  int _N;  // 这里的_N相对于fun函数是全局的!!!!!!!
};

int main() {
  // 函数的例子
  std::cout << "function example:\n";
  std::thread t1(fun, 100000);
  std::thread t2(fun, 100000);
  t1.join();
  t2.join();
  
  std::this_thread::sleep_for(std::chrono::milliseconds(500));

  // 类的例子
  std::cout << "\nclass example:\n";
  C c;
  c._N = 0;
  std::thread t3(&C::fun, &c, 100000);
  std::thread t4(&C::fun, &c, 100000);
  t3.join();
  t4.join();

  return 0;
}

一种可能的执行结果:

function example:
local: 100000
global: 109248
local: 100000
global: 109248

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

C/C++函数的本质以及多线程函数的调用过程 的相关文章

  • 【C++笔记】OpenCV图像Mat格式转换为QT中QImage并显示zai Qlabel上

    Mat rgb QImage imgGray img if imgGray channels 1 imgGray img QImage const unsigned char imgGray data imgGray cols imgGra
  • 【C++】Lambda表达式

    C 11的一大亮点就是引入了Lambda表达式 利用Lambda表达式 可以方便的定义和创建匿名函数 对于C 这门语言来说来说 Lambda表达式 或 匿名函数 这些概念听起来好像很深奥 但很多高级语言在很早以前就已经提供了Lambda表达
  • C语言结构体,共用体所占字节数计算

    字节数 环境 char short int long long long float double 指针 windows 32 gcc 1 2 4 4 8 4 8 4 windows 64 gcc 1 2 4 4 8 4 8 8 无符号型在
  • c++智能指针和普通指针之间相互转换

    include
  • 【OpenCV】噪声的添加和过滤

    1 简介 下面简单介绍两种图像噪声 即椒盐噪声和高斯噪声 1 椒盐噪声 椒盐噪声也称脉冲噪声 它是一种随机出现的白点或者黑点 可能是亮的区域有黑色像素或是在暗的区域有白色像素 或是两者皆有 图像模拟添加椒盐噪声是通过 随机获取像素点 并设置
  • 排序算法浅识

    排序说简单也简单 说复杂某些地方也是有些绕 这里做做笔记 帮助自己记忆和理解常接触的排序算法到底是什么鬼 什么是排序 其实就是排大小啊大佬 排序的稳定性 为何排序的稳定性很重要 在初学排序时会觉得稳定性有这么重要吗 两个一样的元素的顺序有这
  • 【C++】异常处理

    一 什么是异常处理 一句话 异常处理就是处理程序中的错误 二 为什么需要异常处理 以及异常处理的基本思想 C 之父Bjarne Stroustrup在 The C Programming Language 中讲到 一个库的作者可以检测出发生
  • C++之函数重载

    目录 1 函数重载 2 函数重载的概念 3 编译器的工作 4 判断函数重载的规则 1 函数的重复声明 2 参数表的比较过程与形参名无关 3 如果在两个函数的参数表中 4 相同的参数列表 5 形参是按值传递方式定义 6 参定义指针或引用 7
  • C++之运算符重载

    目录 1 运算符重载 1 可实现的对象 编辑2 定义运算符重载函数的一般格式 3 运算符的重载实际 2 为什么要重载 3 前提 4 如何重载 5 默认 6 指针作为数据成员 7 字符串重载 8 友元重载 重载输出 lt lt 运算符 9 运
  • C++的一些概念 面向对象程序的基本特点

    本节主要介绍一些基本概念 有关于面向对象程序的基本特点 Markdown和扩展Markdown简洁的语法 抽象 对某一类对象的共同属性和行为进行概括 形成类 首先注意问题的本质和描述 其次是实现的过程或细节 数据抽象 描述某类对象的属性或状
  • 【C++笔记】《C++编程思想-卷一》笔记

    C 编程思想 笔记 Volume 1 第一章 对象导言 OOP ObjectOriented Programming 面对对象编程 UML Unified Model Language 统一建模语言 堆 stack 和栈 heap 预备知识
  • 【C++笔记】数据结构栈、堆,内存占用中栈区、堆区的区别和理解

    在计算机领域 堆栈是一个不容忽视的概念 我们编写的C语言程序基本上都要用到 但对于很多的初学着来说 堆栈是一个很模糊的概念 堆栈 一种数据结构 一个在程序运行时用于存放的地方 这可能是很多初学者的认识 因为我曾经就是这么想的和汇编语言中的堆
  • sort函数的时间、空间复杂度

    sort函数进行排序的时间复杂度为n log2n 原理 不是简单的快排 STL的sort 算法 数据量大时采用Quick Sort 分段递归排序 一旦分段后的数据量小于某个门槛 为避免Quick Sort的递归调用带来过大的额外负荷 就改用
  • C++基础之初始化、输入输出安全问题及常量问题

    一 C 统一初始化 初始化列表 解决方案 例1 int main int a 10 int b 10 int c 10 初始化列表 int arr 10 1 2 4 5 6 int brr 10 1 2 3 4 5 6 int crr 1
  • 数据结构与算法--分治策略

    目录 1 分治概念 2 递归的概念递归 3 分治策略的 1 分治策略的特征 2 分治法步骤 4 栈的面试题 5 示例 1 示例1求解n的阶乘 1 分析 2 阶乘可递归的定义为 3 递归程序 4 图解递归过程 代码的调动过程 5 图解递归过程
  • VS2010配色方案

    找了很久的配色方案 绝对是精挑细选的 现在分享一下地址 http www hanselman com blog VisualStudioProgrammerThemesGallery aspx 个人喜欢的配色方案 Ragnarok 附图 忘
  • C语言用牛顿迭代法和二分法递归求解三元一次方程

    求解方程 2x 3 4x 2 3x 6 0 牛顿迭代法 牛顿迭代法公式 以下图片均来源于百度 牛顿迭代法用递归实现解三元一次方程 include
  • C语言--swap交换函数

    目录 1 swap1 int a int b 不变 2 swap2 int a int b 不变 3 swap3 int a int b 改变 4 swap4 int a b 改变 1 swap1 int a int b 不变 void s
  • 【C++笔记】NULL、0、nullptr区别分析

    一 C的NULL 在C语言中 我们一般使NULL表示空指针 即 int i NULL foo t f NULL 但是 实际上在C语言中 NULL通常被定义为 define NULL void 0 也就是说NULL实际上是一个void 的指针
  • 二叉树的根到叶子几点之和

    输入 root 1 2 3 输出 25 解释 从根到叶子节点路径 1 gt 2 代表数字 12 从根到叶子节点路径 1 gt 3 代表数字 13 因此 数字总和 12 13 25 输入 root 1 0 1 0 1 0 1 输出 22 解释

随机推荐

  • [288]关于MySQL的1064错误

    MySQL的1064错误是SQL语句写的有问题时出现的 即SQL的语法错误 笔者常常使用MySQL python这个库来对MySQL进行操作 代码中报这个错误的一般是cursor execute sql param 这一行 这种参数式执行S
  • Vue的Ui框架之Mint-UI的使用方法

    基于Vue的Ui框架 饿了么公司基于vue开发的vue的Ui组件库 Element Ui 基于vue pc端的UI框架 MintUi 基于vue 移动端的ui框架 mintUI的使用 1 找官网 2 安装 npm install mint
  • stm32 freeRTOS lwip TCP快速发送,内存泄露问题

    现象1 发送缓慢 tcp write之后要等200多ms才能过发送出去 而且粘包严重 解决办法 tcp write之后 立马调用tcp output tcp就会立马发送 tcp write tcp output 现象2 持续快速发送和接受T
  • linux top VIRT RES SHR SWAP DATA内存参数详解

    总结 VIRT 虚拟内存中含有共享库 共享内存 栈 堆 所有已申请的总内存空间 RES 是进程正在使用的内存空间 栈 堆 申请内存后该内存段已被重新赋值 SHR 是共享内存正在使用的空间 SWAP 交换的是已经申请 但没有使用的空间 包括
  • cookie的读写设计和浏览器控制台Application设计不一致?

    问题描述 在做需求联调的时候发现 用https的链接登录状态验证正常 但是在http协议下 会出现set cookie失败的情况 导致登录状态验证失败 查看控制台 报错如下 提示 会覆盖具有 Secure 属性的cookie 于是在控制台下
  • C语言:以分号结尾的诗

    目录 前言 1 从Hello world开始 2 数据的类型与运算 2 1 整形在内存中的存储 2 1 1 从二进制说起 2 1 2 数据类型 2 1 2 1 数据类型家族 2 1 2 2 比特 字节 2 1 3 原码 反码 补码 2 1
  • cookie保存,json、字符串相互转换

    cookie读写操作 addcookie函数中 对text进行了eacape编码 方便在各种浏览器 下都可以读取 所以取值的时候需要unescape 解码 function getCookie name var strCookie docu
  • Windows下性能最好的I/O模型——完成端口

    Windows下性能最好的I O模型 完成端口 I O模型 完成端口 设计目的 常见的网络通信分为两种 同步和异步 在同步通信中 每一次接受数据都会导致主线程的挂起 从而阻塞住了其他操作 为了解决这一问题 我们通常会采取同步通信 多线程的策
  • 一个关于Python字符串格式化输出的练习

    请实现一个程序 实现如下需求点 1 程序开始的时候提示用户输入学生年龄信息 格式如下 Jack Green 21 Mike Mos 9 我们假设 用户输入 上面的信息 必定会遵守下面的规则 学生信息之间用分号隔开 分号前后可能有不定数量的空
  • 延时函数中用全局变量还是用局部变量

    从不上系统角度 如果中断函数中没有调用延时函数 就都可以 但是如果中断函数中有用到延时函数 就用 局部变量 因此 全部使用局部变量最好
  • 一次磁盘占用率 100% 的排查记录

    一 排查磁盘占用率100 1 1 查看磁盘使用的大致情况 第一个命令就是 df h 来查看磁盘的占用情况 df 是 disk free 的缩写 用于显示目前在 Linux 系统上的文件系统磁盘的使用情况统计 如下图所示 可以看到磁盘占用率
  • Exoplayer+Exomedia之玩转视频播放事件监听

    说明 视频播放事件包括两个部分 1 播放器本身的事件 开始 暂停 结束播放等 2 用户动作触发的事件 拖拽进度条 点击屏幕等 播放事件监听的途径主要是通过视频播放框架 或开发者自定义 的控制器来实现的 控制器是指操作播放器的组件 按钮 进度
  • 信号完整性分析基础知识之传输线和反射(二):阻性负载的反射,源端阻抗,弹跳图

    传输线的端接需要考虑三种重要的特殊情况 每种情况中 传输线的特性阻抗均为50Ohm 信号将从源端在这条传输线上传播 并以特定的阻抗端接到达远端 TIP 在时域中 信号对瞬时阻抗十分敏感 第二区域并不一定是一条传输线 它也可能是一个分立设备
  • Ubuntu14.04上安装TensorRT 2.1操作步骤

    在Ubuntu14 04 上安装TensorRT2 1有两种方法 1 通过 deb直接安装 2 通过Tar文件安装 这里通过Tar文件安装 安装步骤 1 安装CUDA 8 0 可参考 http blog csdn net fengbingc
  • 离散系统Matlab信号处理

    一 离散时间信号 代码 n 2 7 x 0 2 3 5 6 1 5 7 9 2 subplot 2 1 1 stem n x xlabel n ylabel x n title stem函数绘制离散信号 subplot 2 1 2 plot
  • 使用scrapy cluster构建企业级爬虫系统——(2)实现网站深度抓取

    上回博客中 我们对scrapy cluster进行了介绍 今天我们来搭建scrapy cluster的开发环境 这里我使用的开发机环境是Ubuntu 18 04 大家日常如果使用windows开发时候 最好把zookeeper kafka
  • .Xauthority文件 有问题,导致无法登录

    在用户 home目录下的 Xauthority文件 解决办法 1 修改 2 rm 删除 重启
  • 管理习惯---思维转变

    福州 雨 湿热 简单描述 想起了香港的蜗居 当然 中庸的福州美于香港不止一点 参加了 管理他人者 说道执行 涉及内容 确定方向与明确目标 授权与跟进 发张直属下级 评估和改善绩效 选择团队成员和建设团队 时间分配 上级谈话 课程来说 偏向中
  • 【JVM】手写Java虚拟机-01 命令行工具

    目录 介绍 环境 配置环境 可能遇到的问题 开始 命令行工具 执行 介绍 手写一个简单的Java虚拟机 参考了bugstack虫洞栈 声哥 自己动手写Java虚拟机 和JVM Demo 本系列文章尽可能按照保姆级呈现 如果有任何问题和建议
  • C/C++函数的本质以及多线程函数的调用过程

    C C 中 函数的本质是一段可执行代码 代码包括了局部变量 全局变量的地址等等 到汇编语言的级别 变量函数等都可以视为汇编的代码片段 函数的本质就是一个可执行代码片段的集合 线程的详细介绍 http www cnblogs com trac