• [问题求助] 物联网里面的实验
    快速体验恒温空调云端控制有人会吗
  • [训练管理] 训练作业时一直报错
    作业在运行时提示报错,不知道是啥问题了
  • 已完成体验
  • 猫很高冷很可爱wo'hen'
  • [线上活动] 美丽并且还好看的AI绘画
    哈哈哈哈哈哈哈哈哈哈哈哈哈
  • [其他] 少女
    蓝色眼睛,金色头发,jiao'qiao
  • [云数据迁移] 上云方案计划书
    目录前言 1 项目概述 1.1 项目背景 1.2 项目关键信息收集 2 项目需求分析 2.1项目现状分析 2.2 总体需求分析 2.2.1 业务计算部分上云需求 2.2.2 业务存储部分上云需求 2.2.3 业务网络部分上云需求 2.2.4 安全设计需求 2.2.5 其他特殊需求 3 项目方案架构图(预) 4 项目技术方案 4.1 x业务上云技术方案 4.2 y业务上云技术方案 4.3 z业务上云技术方案 4.4 业务整体安全 4.5 迁移技术方案 5 项目实现价值与总结 1 项目概述1.1 项目背景因某地央企投资银行分支需当地上云政策,实现三大系统上云。这三大三大系统分别是:企业办公系统(x)、终端app业务系统(y)、核心业务金融数据汇算系统(z)。同时解决前期三大系统的一些运行问题。1.2 项目关键信息收集有三大系统需要上云:企业办公系统(x)、终端app业务系统(y)、核心业务金融数据汇算系统(z)。1、 企业办公系统(X):运行在华为RH2288,单台,业务后端只能在Centos7.0以上的os运行;员工都只能从本楼内网访问;需要负载均衡,人多有点卡;存储用正常文件存储。2、 终端app业务系统(y):用户接入数常年都很多,注意性能,上云不能卡,业务的数据要做实时读写,网络就对公网开放就好,限制下ICMP3、 核心业务金融数据汇算系统(z):现在承载在本地刀片服务器上,业务后端在虚拟机跑的效果不好,几年前测试过,所以能不用虚拟端部署最好;现在已有2T数据,如果要上云,要2倍数据;数据实时读写要求也很高;网络只能放同我们一台运维主机的ip,10.x.x.x,其他一概拒绝;4、 安全容灾要求:站点尽量别选沿海的,做个本地和异地的容灾设计5、 其他要求:需要资源监控及迁移方案2 项目需求分析2.1项目现状分析客户三大系统目前在本地运行,根据本地政府要求必须上云。用户三大系统在人多使用时会有卡顿,机房遭受过台风袭击,有比较迫切的上云及容灾需求。2.2 总体需求分析2.2.1 业务计算部分上云需求1、 企业办公系统(X):目前运行在本地单台华为RH2288上,业务后端只能在Centos7.0以上的os运行;2、 终端app业务系统(y):用户接入数常年都很多,注意性能,上云不能卡3、 核心业务金融数据汇算系统(z):现在承载在本地刀片服务器上,个z业务后端在虚拟机跑的效果不好,几年前测试过,所以能不用虚拟端部署最好;2.2.2 业务存储部分上云需求1、 企业办公系统(X):存储用正常文件存储,容量未说明,具体根据客户要求选用2、 终端app业务系统(y):数据需要实时读写,容量未说明,具体根据客户要求选用3、 核心业务金融数据汇算系统(z):现在已经有2个T的数据了,上云,要2倍,也就是4T空间,也需要数据实时读写2.2.3 业务网络部分上云需求1、 企业办公系统(X):员工都只能从本楼内网访问;上云需要负载均衡。2、 终端app业务系统(y):用户接入数常年都很多,网络就对公网开放就好,限制下ICMP3、 核心业务金融数据汇算系统(z):网络只能放同我们一台运维主机的ip,10.x.x.x,其他一概拒绝2.2.4 安全设计需求站点尽量别选沿海的,做本地和异地的容灾设计2.2.5 其他特殊需求需要资源监控及迁移方案3 项目方案架构图(预)4 项目技术方案4.1 x业务上云技术方案1、 客户需求:企业办公业务上云需要进行负载均衡进行分流,同时保证业务不卡,还需要在内网使用。2、 上云建议:用两台ECS(系统centos7.0以上,具体配置根据用户需求选择),下挂文件服务SFS,前面加上负载均衡ELB,通过云专线或云VPN与用户办公室相连,实现上云及办公室业务人员连接要求。4.2 y业务上云技术方案1、 客户需求:终端App业务系统,用户连接数多,需要高性能,保证公网用户使用不卡;数据需实时读写2、 上云建议:开1台高性能ECS,申请一个EIP与internet互联,对公网用户开放;同时要保证安全,使用安全组SG阻止ICMP访问;开通EVS云硬盘。4.3 z业务上云技术方案1、 客户需求:核心金融汇算业务,无法虚拟化,数据实时读写要求高,需要4T空间,只放通一台运维主机。2、 上云建议:使用BMS服务,同时使用ACL/SG限制,只放通一台运维主机(ip,10.x.x.x)访问;开通4TEVS云硬盘挂载。4.4 业务整体安全根据用户需求,选择内陆region开通业务,同时通过SDRS和CBR部署云上两地三中心容灾4.5 迁移技术方案迁移分为迁移前调研、迁移上云评估、迁移方案制定、迁移方案测试(验证方案的正确性及可实施性,工具选择验证等)、迁移分级分布实施(先迁普通业务再迁核心业务)、迁移验收测试、迁移维保等阶段展开4.6 云资源监控及运维建议云上资源监控可以使用免费的CTS(云审计)、CES(云监控)、LTS(日志审计)三个服务对资源进行监控。云上资源运维建议开通CBH(云堡垒机)进行运维,可以保证运维安全且可以审计追溯等。5 项目实现价值与总结该项目可实现用户三大系统上云需求,同时解决用户现网访问卡顿的问题,而且实现了用户的两地三中心的灾备需求,极大地保障了用户业务连续性和安全性。
  • [其他] Muse AI绘画 美女 纯欲 氛围感 细节
    ii美女 纯欲 氛围感 细节描绘 精致wu'guan
  • [专题汇总] Linux开发基础专题总汇(一)
    一、前言传统的Linux在内核的基础上,经过缩减可以移植到嵌入式操作系统上面也就是所谓的物联网设备,后来很多商业公司和开源组织对Linux系统进行了一番改造,使其更加适用于嵌入式系统和物联网应用的需求,就是修改为实时操作系统。目前主流的基于Linux系统的实时操作系统有RTLinux、Brillo、uClinux、Ostro Linux、LiteOS、OpenWrt、Tizen、Snappy Ubuntu Core等等,他们背后都有着不同的商业公司或者主流的社区用户支持。上述系统对专业性的方面我也是没那个能力评价,就以现在pc和手机市场上的操作系统的现状来看,决定系统最后辉煌发展的必定是用户和生态这两个重要因素。因为Linux系统基础上发展起来的面向物联网应用的系统项目非常之多,Linux碎片化的情形也比较严重的事情,这时候产生割裂,对于开发者来说是非常不好的局面。二、Linux系统下基础命令与Makefile使用基础命令https://bbs.huaweicloud.com/forum/thread-0264102134841708046-1-1.htmlLinux是一套免费使用和自由传播的类Unix操作系统,是一个基于POSIX和UNIX的多用户、多任务、支持多线程和多CPU的操作系统。它能运行主要的UNIX工具软件、应用程序和网络协议。它支持32位和64位硬件。Linux继承了Unix以网络为核心的设计思想,是一个性能稳定的多用户网络操作系统。Linux操作系统诞生于1991 年10 月5 日(这是第一次正式向外公布时间)。Linux存在着许多不同的Linux版本,但它们都使用了Linux内核。Linux可安装在各种计算机硬件设备中,比如手机、平板电脑、路由器、视频游戏控制台、台式计算机、大型机和超级计算机。Linux系统-Makefile规则介绍、基本使用 https://bbs.huaweicloud.com/forum/thread-0299102303834721003-1-1.htmlLinux 环境下的程序员如果不会使用GNU make来构建和管理自己的工程,应该不能算是一个合格的专业程序员,至少不能称得上是 Unix程序员。在 Linux(unix )环境下使用GNU 的make工具能够比较容易的构建一个属于你自己的工程,整个工程的编译只需要一个命令就可以完成编译、连接以至于最后的执行。不过这需要我们投入一些时间去完成一个或者多个称之为Makefile 文件的编写。所要完成的Makefile 文件描述了整个工程的编译、连接等规则。其中包括:工程中的哪些源文件需要编译以及如何编译、需要创建哪些库文件以及如何创建这些库文件、如何最后产生我们想要的可执行文件。尽管看起来可能是很复杂的事情,但是为工程编写Makefile 的好处是能够使用一行命令来完成“自动化编译”,一旦提供一个(通常对于一个工程来说会是多个)正确的 Makefile。编译整个工程你所要做的事就是在shell 提示符下输入make命令。整个工程完全自动编译,极大提高了效率。make是一个命令工具,它解释Makefile 中的指令。在Makefile文件中描述了整个工程所有文件的编译顺序、编译规则。Makefile 有自己的书写格式、关键字、函数。像C 语言有自己的格式、关键字和函数一样。而且在Makefile 中可以使用系统shell所提供的任何命令来完成想要的工作。Makefile在绝大多数的IDE 开发环境中都在使用,已经成为一种工程的编译方法。三、Linux下线程知识点Linux下(pthread)线程创建与使用 https://bbs.huaweicloud.com/forum/thread-0288102303912787002-1-1.html前面文章介绍了Linux下进程的创建、管理、使用、通信,了解了多进程并发;这篇文章介绍Linux下线程的基本使用。线程与进程的区别 (1)进程: 是操作系统调度最小单位。 Linux下可以通过ps、top等命令查看进程的详细信息。 (2)线程: 是进程调度的最小单位,每个进程都有一个主线程。在进程里主要做事情就是线程。(3)在全系统中,进程ID是唯一标识,对于进程的管理都是通过PID来实现的。每创建一个进程,内核去中就会创建一个结构体来存储该进程的全部信息,每一个存储进程信息的节点也都保存着自己的PID。需要管理该进程时就通过这个ID来实现(比如发送信号)。当子进程结束要回收时(子进程调用exit()退出或代码执行完),需要通过wait()系统调用来进行,未回收的消亡进程会成为僵尸进程,其进程实体已经不复存在,但会虚占PID资源,因此回收是有必要的。对于线程而言,若要主动终止需要调用pthread_exit() ,主线程需要调用pthread_join()来回收(前提是该线程没有设置 “分离属性”)。像线发送线程信号也是通过线程ID实现进程间的通信方式: A.共享内存 B.消息队列 C.信号量 D.有名管道 E.无名管道 F.信号 G.文件 H.socket 线程间的通信方式: A.互斥量 B.自旋锁 C.条件变量 D.读写锁 E.线程信号 F.全局变量进程间采用的通信方式要么需要切换内核上下文,要么要与外设访问(有名管道,文件)。所以速度会比较慢。而线程采用自己特有的通信方式的话,基本都在自己的进程空间内完成,不存在切换,所以通信速度会较快。也就是说,进程间与线程间分别采用的通信方式,除了种类的区别外,还有速度上的区别。说明: 当运行多线程的进程捕获到信号时,只会阻塞主线程,其他子线程不会影响会继续执行。Linux系统下(pthread)线程的使用案例(分离属性、清理函数等) https://bbs.huaweicloud.com/forum/thread-0254102303978648006-1-1.htmlIOT开发基础知识系列--Linux(pthread)线程通信(互斥锁) https://bbs.huaweicloud.com/forum/thread-0254105157013717018-1-1.htmlIOT开发基础知识系列--(pthread)线程通信(条件变量) https://bbs.huaweicloud.com/forum/thread-0283105157071489019-1-1.htmlIOT开发基础知识系列--Linux(pthread)线程通信(围栏机制) https://bbs.huaweicloud.com/forum/thread-0254105157128971019-1-1.htmlIOT开发基础知识系列--Linux(pthread)线程通信(信号量) https://bbs.huaweicloud.com/forum/thread-0246105157181656018-1-1.htmlIOT开发基础知识系列--Linux(pthread)线程通信(自旋锁) https://bbs.huaweicloud.com/forum/thread-0281105157230115016-1-1.htmlIOT开发基础知识系列--Linux-Shell脚本基本使用(变量、运算符、语句等) https://bbs.huaweicloud.com/forum/thread-0245105157301998020-1-1.htmlIOT开发基础知识系列--Linux-进程创建(fork)、外部程序调用(exec) https://bbs.huaweicloud.com/forum/thread-0246105157380708019-1-1.htmlIOT开发基础知识系列--Linux进程概念、进程管理、信号处理 https://bbs.huaweicloud.com/forum/thread-0246105157436893020-1-1.htmlIOT开发基础知识系列--Linux-进程间通信(mmap内存映射) https://bbs.huaweicloud.com/forum/thread-0245105157513178021-1-1.htmlC语言——链表总结 https://bbs.huaweicloud.com/forum/thread-0257104982341137018-1-1.html
  • 从卡塔尔世界杯看物联网->智慧足球场
    北京时间2022年11月20日晚,卡塔尔世界杯正式开幕。作为四年一届的足坛盛宴,受到举世瞩目。除了赛场的顶级配备之外,此次卡塔尔世界杯,无论是足球或是判罚机制还是球场环境,都充斥着“黑科技”,物联网早已“渗透”到国际顶级赛事中,为其服务与赋能。而由中国铁建一体承包设计与施工的卡塔尔世界杯主球场——卢塞尔体育场,更是为人称道,堪称当今顶级“智慧体育场”的典范!提及智慧体育场,早在2021年10月,国家体育总局发布《“十四五”体育发展规划》,在数字体育建设工程专栏明确提出要“加快体育场地设施数字化改造,推动地方数字化升级改造不少于1000个体育场馆,打造一批智慧体育场馆”,为“十四五”时期体育场馆发展指明了方向。新型智慧化体育场,可广泛应用物联网技术,从感知层打造基础,从连接层传输数据,从应用层优化管理。1、感知赋能,LoRaWAN传感器让足球场拥有“感受” 足球场作为大型的足球活动和赛事的承载场所,由于建设封闭式体育场费用高昂、便于赛事活动开展等原因,通常建设为露天运动场,此次卡塔尔世界杯的各大赛场亦如此。因此,针对足球场的环境监测也就成了重中之重。2、提速提质,5G系列产品让赛事活动连接更“流畅” 赛事活动举办期间,必定会受到多方关注。线下人群拥挤,网络覆盖范围小,网络信号差;线上观众聚集,网速卡顿,无法畅快观赛。无论是感知层,还是连接层,运用IoT技术打造“物联网+智慧足球场”,夯实底层基础,创新顶层设计,才可真正满足人民群众健身健康、体育消费需求,提高全民健身、体育赛事智慧化服务水平。
  • [技术干货] IOT开发基础知识系列--Linux-进程间通信(mmap内存映射)
    前面文章介绍了进程间常用的通信方式: 无名管道和命名管道,这篇文章介绍内存映射,内存映射在多进程访问文件读写的时候非常方便。1. 内存映射mmap函数介绍mmap函数可以将磁盘上的文件映射到内存空间中,返回映射的首地址。相关函数: mmap munmap msync函数原型与参数介绍:#include <unistd.h> #include <sys/mman.h> int msync(const void *start, size_t length, int flags); 函数功能: 把对内存区域所做的更改同步到文件 void *mmap(void *addr, size_t length, int prot, int flags,int fd, off_t offset); 函数功能: 用来将某个文件内容映射到内存中,对该内存区域的存取即是直接对该文件内容的读写。通过这样可以加快文件访问速度。 返回值:成功返回映射的内存的起始地址。 (1) 第一个参数start指向欲对应的内存起始地址,通常设为NULL,代表让系统自动选定地址,对应成功后该地址会返回。 (2) 第二个参数length代表将文件中多大的部分对应到内存。 (3) 第三个参数prot代表映射区域的保护方式有下列组合: PROT_EXEC 映射区域可被执行 PROT_READ 映射区域可被读取 PROT_WRITE 映射区域可被写入 PROT_NONE 映射区域不能存取 (4) 第四个参数 flags会影响映射区域的各种特性: MAP_FIXED 如果参数start所指的地址无法成功建立映射时,则放弃映射,不对地址做修正。通常不鼓励用此旗标。 MAP_SHARED 对映射区域的写入数据会复制回文件内,而且允许其他映射该文件的进程共享。 MAP_PRIVATE 对映射区域的写入操作会产生一个映射文件的复制,即私人的“写入时复制”, 对此区域作的任何修改都不会写回原来的文件内容。 MAP_ANONYMOUS 建立匿名映射。此时会忽略参数fd,不涉及文件,而且映射区域无法和其他进程共享。 MAP_DENYWRITE 只允许对映射区域的写入操作,而不能对fd指向的文件进行读写,对该文件直接写入的操作将会被拒绝。 MAP_LOCKED 将映射区域锁定住,这表示该区域不会被置换(swap)。 在调用mmap()时必须要指定MAP_SHARED 或MAP_PRIVATE。 (5) 第五个参数fd为open()返回的文件描述词,代表欲映射到内存的文件。 (6) 第六个参数offset为文件映射的偏移量,通常设置为0,代表从文件最前方开始对应,offset必须是分页大小的整数倍。 用法示例: fb_mem=mmap(NULL,smem_len,PROT_READ|PROT_WRITE,MAP_SHARED,fb,0); int munmap(void *addr, size_t length); 函数功能: 取消映射,用来取消参数start所指的映射内存起始地址,参数length则是欲取消的内存大小。当进程结束,映射内存会自动解除,但关闭对应的文件描述词时不会解除映射。返回值:如果解除映射成功则返回0,否则返回-1。 通过内存映射进行进程通信,多个进程可以同时映射同一个文件到内存空间,只要一个进程对文件进行了修改,其他进程都可以得到修改的数据。 注意: 打开文件的权限需要与映射的权限一致!2. 案例代码: mmap用法示例(1)下面代码的功能: 创建一个新文件,设置文件大小,使用mmap函数映射文件地址出来,对地址直接拷贝数据进入,再取消映射。 这时再打开文件,数据已经存放到到文件中了。演示通过mmap映射文件地址方式读写文件。#include <stdio.h> #include <unistd.h> #include <string.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <dirent.h> #include <stdlib.h> #include <sys/mman.h> int main(int argc,char **argv) { if(argc!=2) { printf("./a.out <文件>\n"); return 0; } /*1. 创建一个文件*/ int fd; fd=open(argv[1],O_RDWR|O_CREAT,S_IRWXU); if(fd<0) { printf("%s 文件打开失败.\n",argv[1]); return 0; } /*2. 设置文件的大小*/ ftruncate(fd, 1024); /*3. 获取文件大小*/ struct stat s_buf; fstat(fd,&s_buf); printf("文件的大小:%d Byte\n",s_buf.st_size); /*4. 映射文件到内存空间*/ unsigned char *mem_p=NULL; mem_p=mmap(NULL,s_buf.st_size,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0); if(mem_p==NULL) { printf("文件映射失败.\n"); close(fd); return 0; } /*5. 关闭文件*/ close(fd); /*6. 实现文件读写*/ strcpy(mem_p,"mmap函数测试.实现文件读写."); /*7. 打印文件里的内容*/ printf("mem_p=%s\n",mem_p); /*8. 取消映射*/ munmap(mem_p,s_buf.st_size); return 0; }3. 案例代码: mmap用法示例(2)下面代码的功能: 程序运行时,从命令行传入一个存在的文件路径进去,再调用open打开文件,再通过mmap映射文件地址,得到地址之后向文件拷贝一串字符串数据进去。注意: 通过mmap映射的地址写数据一定要保证范围不能超过文件的本身大小范围。超过就段错误了。#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <sys/mman.h> #include <sys/types.h> #include <sys/stat.h> #include <string.h> char buff[]="内存映射测试"; int main(int argc,char **argv) { if(argc!=2) { printf("./app <文件>\n"); return 0; } char *m_p; struct stat stat_buf; stat(argv[1],&stat_buf); int fd=open(argv[1],O_RDWR); m_p=mmap(0,stat_buf.st_size,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0); if(m_p!=NULL)printf("映射成功!\n"); printf("m_p=%s\n",m_p); //memset(m_p,0,stat_buf.st_size); memcpy(m_p,buff,strlen(buff)); munmap(m_p,stat_buf.st_size); close(fd); return 0; }4. 案例代码: 多进程并发拷贝一个大文件代码要求: 使用mmap函数映射文件到内存。 memcpy() 使用多进程并发拷贝一个大文件,巩固mmap的用法 详细要求: 创建5个子进程同时拷贝一个文件,每个进程拷贝文件的一部分。 设置指定文件的大小:int truncate(const char *path, off_t length) 示例代码:#include <stdio.h> #include <unistd.h> #include <string.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <dirent.h> #include <stdlib.h> #include <sys/mman.h> #include <sys/wait.h> //定义子进程的数量 #define FORK_NUMBER 4 /* 实现多进程并发拷贝大文件---mmap */ int main(int argc,char **argv) { if(argc!=3) { printf("./a.out <拷贝的源文件> <新文件>\n"); return 0; } /*1. 打开源文件*/ int src_fd=open(argv[1],O_RDWR); if(src_fd<0) { printf("%s 源文件打开失败.\n",argv[1]); return -1; } /*2. 创建新文件*/ int new_fd=open(argv[2],O_RDWR|O_CREAT,S_IRUSR|S_IWUSR); if(new_fd<0) { printf("%s 新文件创建失败.\n",argv[2]); return -2; } /*3. 获取源文件大小设置新文件的大小*/ struct stat s_buff; fstat(src_fd,&s_buff); printf("源文件的字节大小:Þ420053c-f357-4b6b-b180-d4821ddade71n",s_buff.st_size); ftruncate(new_fd,s_buff.st_size); /*4. 映射源文件到内存空间*/ unsigned char *src_p; src_p=mmap(NULL,s_buff.st_size,PROT_READ|PROT_WRITE,MAP_SHARED,src_fd,0); if(src_p==NULL) { close(src_fd); printf("源文件映射失败.\n"); return -3; } /*5. 映射新文件到内存空间*/ unsigned char *new_p; new_p=mmap(NULL,s_buff.st_size,PROT_READ|PROT_WRITE,MAP_SHARED,new_fd,0); if(new_p==NULL) { close(new_fd); printf("新文件映射失败.\n"); return -4; } /*6. 关闭文件*/ close(new_fd); close(src_fd); /*7. 计算子进程和父进程拷贝的文件字节大小*/ int cp_size; int main_size; cp_size=s_buff.st_size/FORK_NUMBER; //每个子进程拷贝的大小 main_size=s_buff.st_size%FORK_NUMBER; //父进程拷贝的大小 /*8. 创建子进程*/ int i; for(i=0;i<FORK_NUMBER;i++) { if(fork()==0)break; } /*9. 子进程完成文件的拷贝*/ if(i<FORK_NUMBER) //表示就是子进程 { memcpy(new_p+i*cp_size,src_p+i*cp_size,cp_size); munmap(new_p,s_buff.st_size); munmap(src_p,s_buff.st_size); } else //父进程 { memcpy(new_p+i*cp_size,src_p+i*cp_size,main_size); munmap(new_p,s_buff.st_size); munmap(src_p,s_buff.st_size); pid_t pid; while(1) { pid=wait(NULL); if(pid==-1)break; printf("%d 子进程退出成功.\n",pid); } printf("父进程退出成功.\n"); } return 0; }
  • [技术干货] IOT开发基础知识系列--Linux进程概念、进程管理、信号处理
    1. 进程知识点操作系统里的进程是程序一次执行的过程,是操作系统动态执行的基本单元;每当创建新的进程后,操作系统会为新的进程分配一个唯一的标识符,方便后续管理进程。进程的概念主要有两点:第一,进程是一个实体。每个进程都有自己的虚拟地址空间,包括文本区、数据区、和堆栈区。文本区域存储处理器执行的代码;数据区存储变量和动态分配的内存;堆栈区存储着活动进程调用的指令和本地变量。第二,进程是一个“执行中的程序”,它和程序有本质区别。程序是静态的,它是一些保存在磁盘上的指令的有序集合;而进程是一个动态的概念,它是一个运行着的程序,包含了进程的动态创建、调度和消亡的过程,是Linux的基本调度单位。只有当处理器赋予程序生命时,它才能成为一个活动的实体,称之为进程。Linux在命令行上可以用ps命令查看后台运行的进程详细信息。2. 查看可执行文件的内部空间布局进程是动态的(内存里的)、程序是静态的_a.out(硬盘上)。 Linux下进程都是运行在虚拟地址空间的---MMU。每个进程的空间是独立的(物理地址)。[wbyq@wbyq linux_c]$ gcc app.c [wbyq@wbyq linux_c]$ ls a.out app.c shell.sh [wbyq@wbyq linux_c]$ ./a.out [wbyq@wbyq linux_c]$ size a.out text data bss dec hex filename 960 248 8 1216 4c0 a.out text :文本段. 程序里存放逻辑代码的大小. if while .... data :数据段. 程序里已经初始化过的全局变量和静态变量的大小. bss :BSS段. 程序里未初始化的全局变量和静态变量的大小. dec :十进制格式的程序总大小 hex :十六进制格式的程序总大小 filename :文件的名称3. 进程前台与后台切换方式[wbyq@wbyq linux_c]$ ./a.out & 后台运行 [1] 14705 [wbyq@wbyq linux_c]$ jobs 查看后台运行的进程 [1]+ Running ./a.out & [wbyq@wbyq linux_c]$ fg 1 将后台进程切换到前台 ./a.out ^Z [1]+ Stopped ./a.out [wbyq@wbyq linux_c]$ jobs [1]+ Stopped ./a.out [wbyq@wbyq linux_c]$ bg 1 将后台停止的进程变为执行状态 [1]+ ./a.out & [wbyq@wbyq linux_c]$ jobs [1]+ Running ./a.out & [wbyq@wbyq linux_c]$ fg 1 ./a.out4. kill命令4.1 查看合法信号Kill命令是给进程发送信号. 当前系统可以发送的合法信号有哪些? 通过kill -l[wbyq@wbyq linux_c]$ kill -l 1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP 6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1 11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM 16) SIGSTKFLT 17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP 21) SIGTTIN 22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ 26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO 30) SIGPWR 31) SIGSYS 34) SIGRTMIN 35) SIGRTMIN+1 36) SIGRTMIN+2 37) SIGRTMIN+3 38) SIGRTMIN+4 39) SIGRTMIN+5 40) SIGRTMIN+6 41) SIGRTMIN+7 42) SIGRTMIN+8 43) SIGRTMIN+9 44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13 48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12 53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9 56) SIGRTMAX-8 57) SIGRTMAX-7 58) SIGRTMAX-6 59) SIGRTMAX-5 60) SIGRTMAX-4 61) SIGRTMAX-3 62) SIGRTMAX-2 63) SIGRTMAX-1 64) SIGRTMAX 4.2 如何发送信号?kill [-s signal|-p] [--] pid... kill -l [signal] 用法: kill -s <信号> <进程PID> kill -信号 <进程PID> [wbyq@wbyq linux_c]$ ps PID TTY TIME CMD 9877 pts/0 00:00:01 bash 14983 pts/0 00:00:01 a.out 14984 pts/0 00:00:00 ps [wbyq@wbyq linux_c]$ kill -s 2 149834.3 C语言程序如何捕获信号?#include <stdio.h> #include <signal.h> #include <stdlib.h> void sighandler(int sig) { printf("sig=Óa438e10-b6c7-4fe6-bf10-092e23d55e4dn",sig); exit(0); } int main() { signal(SIGINT,sighandler); while(1) { } return 0; }5. ps命令[wbyq@wbyq linux_c]$ ps -aux Warning: bad syntax, perhaps a bogus '-'? See /usr/share/doc/procps-3.2.8/FAQ USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND root 1 0.0 0.0 2880 1432 ? Ss Aug16 0:06 /sbin/init root 2 0.0 0.0 0 0 ? S Aug16 0:00 [kthreadd] root 3 0.0 0.0 0 0 ? S Aug16 0:03 [migration/0] root 4 0.0 0.0 0 0 ? S Aug16 0:18 [ksoftirqd/0] root 5 0.0 0.0 0 0 ? S Aug16 0:00 [migration/0] root 6 0.0 0.0 0 0 ? S Aug16 0:07 [watchdog/0] root 7 0.0 0.0 0 0 ? S Aug16 0:05 [migration/1] root 8 0.0 0.0 0 0 ? S Aug16 0:00 [migration/1] root 9 0.0 0.0 0 0 ? S Aug16 0:20 [ksoftirqd/1] root 10 0.0 0.0 0 0 ? S Aug16 0:14 [watchdog/1] root 11 0.0 0.0 0 0 ? S Aug16 0:46 [events/0] root 12 0.0 0.0 0 0 ? S Aug16 1:18 [events/1] USER: 启动该进程的用户账号名称 PID: 该进程的 ID 号,在当前系统中是唯一的 %CPU: CPU 占用的百分比 %MEM: 内存占用的百分比 VSZ: 占用虚拟内存(swap 空间)的大小 RSS: 占用常驻内存(物理内存)的大小 TTY: 该进程在哪个终端上运行。 “? ”表未知或不需要终端 STAT: 显示了进程当前的状态。 D 不可中断的休眠。通常是 IO。 R 运行。正在运行或者在运行队列中等待。 S 休眠。在等待某个事件,信号。 T 停止。进程接收到信息 SIGSTOP, SIGSTP, SIGTIN, SIGTOU 信号。 X 死掉的进程,不应该出现。 Z 僵死进程。 通常还会跟随如下字母表示更详细的状态。 < 高优先级 N 低优先级 L 有 pages 在内存中 locked。用于实时或者自定义 IO。 s 进程领导者,其有子进程。 l 多线程 + 位于前台进程组。 START: 启动该进程的时间. TIME: 进程使用的总 CPU 时间 COMMAND: 启动该进程的命令的名称
  • [技术干货] IOT开发基础知识系列--Linux-进程创建(fork)、外部程序调用(exec)
    1. fork函数介绍在linux中fork函数是非常重要的函数,它可以从已存在进程中创建一个新进程。新进程为子进程,而原进程为父进程。fork函数的返回值如下: 1、在父进程中,fork返回新创建的子进程的PID号。 2、在子进程中,fork返回0; 3、如果出现错误,fork返回一个负值。 因此可以通过返回值来判断是父进程还是子进程。fork函数创建子进程的过程: 使用fork函数得到的子进程是父进程的一个复制品,它从父进程继承了进程的所有资源,相当于就是父进程的一个副本。#include <unistd.h> pid_t fork(void); 制作分身 函数功能: 创建新的子进程. 子进程是父的进程一个副本. (分身) 返回值: >0表示父进程 ==0表示子进程示例代码:#include <stdio.h> #include <signal.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> int main() { int a=888; //创建新的子进程 pid_t pid=fork(); if(pid==0) //子进程 { a=999; printf("子进程_a=Û3e72eeb-a2e3-4b5c-b79e-c0fb895a3c97n",a); printf("子进程的PID号:Û3e72eeb-a2e3-4b5c-b79e-c0fb895a3c97n",getpid()); printf("当前子进程的父进程PID号:Û3e72eeb-a2e3-4b5c-b79e-c0fb895a3c97n",getppid()); } else { sleep(1); } return 0; }2. wait函数#include <sys/types.h> #include <sys/wait.h> pid_t wait(int *status); 函数功能: 随机等待一个子进程退出. 如果等待的子进程正常结束,返回值就是该子进程的pid号 如果父进程没有子进程正在运行,wait函数会立即返回,返回值为-1 pid_t waitpid(pid_t pid, int *status, int options); 函数功能: 等待指定的子进程退出.正常的多进程并发设计,父进程要负责清理子进程的空间:#include <stdio.h> #include <signal.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <sys/wait.h> int main() { pid_t pid=fork(); if(pid==0) { printf("子进程运行成功.pid=Û3e72eeb-a2e3-4b5c-b79e-c0fb895a3c97n",getpid()); } else { pid=wait(NULL); //等待子进程退出,清理子进程的空间 printf("退出的子进程的pid=Û3e72eeb-a2e3-4b5c-b79e-c0fb895a3c97n",pid); } return 0; }3. exec系列函数exec系列函数是用于启动一个新的进程,将新的进程启动成功之后会覆盖原进程.#include <unistd.h> extern char **environ; int execl(const char *path, const char *arg, ...); int execlp(const char *file, const char *arg, ...); int execle(const char *path, const char *arg,..., char * const envp[]); int execv(const char *path, char *const argv[]); int execvp(const char *file, char *const argv[]); p表示支持从环境变量里搜索可执行文件.示例代码:#include <stdio.h> #include <signal.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <sys/wait.h> #include <unistd.h> int main() { //ls -l //execl("/bin/ls","ls","-l",NULL); //execlp("ls","ls","-l",NULL); char *cmd[]={"ls","-l",NULL}; //execv("/bin/ls",cmd); //execvp("ls",cmd); char *cmd_path[]={"wbyq=666","abcd=888",NULL}; execle("/bin/ls","ls","-l",NULL,cmd_path); printf("exec函数执行失败.\n"); return 0; }4. system函数system函数用于启动新的子进程,这个函数内部就是使用fork+exec+wait函数组合实现的。 说明这个system函数是阻塞的,必须等待子进程执行完毕之后才会执行父进程的代码。#include <stdlib.h> int system(const char *command);示例代码:#include <stdio.h> #include <signal.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <sys/wait.h> #include <unistd.h> int main() { printf("开始执行.\n"); system("sleep 5"); printf("执行结束.\n"); return 0; }5. popen函数#include <stdio.h> FILE *popen(const char *command, const char *type);函数功能: 启动一个新的进程--类似于fopen --dup2函数 启动成功的返回值的指针就指向该进程的标准输出。int pclose(FILE *stream);函数功能: 释放空间 示例代码: #include <stdio.h> int main() { FILE *fp; char buff[1024+1]; int cnt; fp=popen("/bin/ls *.sh","r"); cnt=fread(buff,1,1024,fp); buff[cnt]='\0'; printf("buff=%s\n",buff); pclose(fp); return 0; }6. pkill 命令(1) pkill 命令支持一次性杀死某用户的所有进程。 $ pkill -u <用户名> (2) pkill 命令支持一次杀死指定名称的所有进程。 $ pkill <应用名称> (3) 使用 killall 命令一次杀死指定名称的所有进程 $ killall <应用名称> (4) 杀死父进程创建的所有子进程 pkill -9 -P <父进程 PID>7. 案例: 使用fork函数创建5个子进程同时运行#include <stdio.h> #include <unistd.h> int main() { int i; pid_t pid; for(i=0;i<5;i++) { pid=fork(); //创建一个子进程 if(pid==0)break; //如果是子进程就直接退出循环 } if(i==5) //父进程 { sleep(5); char cmd_buff[100]; sprintf(cmd_buff,"pkill -9 -P %d",getpid()); system(cmd_buff); while(1) { pid=wait(NULL); if(pid==-1)break; //当父进程没有子进程的时候该函数就返回-1 else printf("%d 子进程退出成功.\n",pid); } printf("父进程正常结束.\n"); } else //子进程 { while(1) { sleep(1); printf("当前运行的子进程pid=Û3e72eeb-a2e3-4b5c-b79e-c0fb895a3c97n",getpid()); } } return 0; }8. 案例: 实现自动切换(2秒)显示指定目录下的所有图片利用eog命令,配合今天学习的进程知识点,做出一个ppt播放效果。 思路: 父进程扫描目录,得到目录下的文件名称,在传递给子进程,子进程调用eog命令实现图片显示,父进程里2秒钟之后就杀死子进程,再读取目录下下一个文件,再传递给子进程………#include <stdio.h> #include <unistd.h> #include <string.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <sys/types.h> #include <dirent.h> #include <stdlib.h> int main(int argc,char **argv) { if(argc!=2) { printf("./a.out <图片目录/>\n"); return 0; } /*1. 打开目录*/ DIR *dir=opendir(argv[1]); if(dir==NULL) { printf("%s 目录打开失败.\n",argv[1]); return 0; } /*2. 创建管道文件*/ int fds[2]; pipe(fds); pid_t pid; struct dirent *dir_info; AA: /*循环遍历目录*/ dir_info=readdir(dir); if(dir_info==NULL) { printf("图片显示完毕.\n"); exit(0); //表示图片显示完毕 } /*创建子进程*/ pid=fork(); if(pid==0) //子进程 { char file_name[100+1]; int cnt; //从管道的读端读取数据 cnt=read(fds[0],file_name,100); file_name[cnt]='\0'; printf("正在显示的图片:%s\n",file_name); //启动新的进程 execlp("eog","eog",file_name,NULL); } else //父进程 { //判断是否是图片 if(strstr(dir_info->d_name,".jpg")) { char *p; //组合图片的路径 p=malloc(strlen(argv[1])+strlen(dir_info->d_name)+1); sprintf(p,"%s%s",argv[1],dir_info->d_name); //向管道的写端写数据 write(fds[1],p,strlen(p)); //延时2秒 sleep(2); //杀死父进程创建的所有子进程 char cmd_buff[100]; sprintf(cmd_buff,"pkill -9 -P %d",getpid()); system(cmd_buff); //清理子进程的空间 wait(NULL); } //继续显示下一张图片 goto AA; } return 0; }
  • [技术干货] IOT开发基础知识系列--Linux-Shell脚本基本使用(变量、运算符、语句等)
    1. Shell脚本介绍Shell 本身是一个用 C 语言编写的程序, Shell 作为命令语言时,可以交互式地解释和执行用户输入的命令;作为程序设计语言时,支持定义各种变量和参数,并提供了许多在高级语言中才具有的控制结构,包括循环和分支。shell脚本的后缀一般是.sh,后缀只是方便用户部分这是个脚本文件。就像windows下的.bat后缀文件一样的道理。Shell 脚本不需要编译,是依靠解析器解析运行,只要有一个能编写代码的文本编辑器和一个能解释执行的脚本解释器就可以了。所以效率上是没有编译型语言速度快,不适合写大量运算的代码。Linux 下的 Shell 解释器种类众多,当前系统的支持的解释器可以在/etc/shells 文件里查看:[wbyq@wbyq linux_c]$ cat /etc/shells /bin/bash /sbin/nologin /bin/tcsh /bin/csh查看当前系统默认的 shell:[xiao@localhost file_2]$ ls -l /bin/sh lrwxrwxrwx 1 root root 4 05-25 19:24 /bin/sh -> bash如果在脚本里想使用其他解释器,可以使用以下语法进行指定:#!/bin/bash#!告诉系统其后路径所指定的程序即是解释此脚本文件的 Shell 程序下面就介绍Shell脚本的基础语法规则、基本使用案例。2. Shell脚本的基本语法规则创建一个简单的脚本文件并运行:[wbyq@wbyq linux_c]$ vim shell.sh [wbyq@wbyq linux_c]$ ls /bin/sh -l lrwxrwxrwx. 1 root root 4 7月 1 2019 /bin/sh -> bash [wbyq@wbyq linux_c]$ ls shell.sh [wbyq@wbyq linux_c]$ ./shell.sh 12345 jsdsdsd [wbyq@wbyq linux_c]$ sh shell.sh 12345 jsdsdsdShell脚本一些规则总结:在脚本代码里#表示注释,并且只是支持单行注释.#! 是用来指定脚本解释器,#!是一个整体. 比如: #!/bin/bash脚本文件编写之后需要将文件权限改为可执行才可以直接运行3. shell变量基本使用#!/bin/bash cnt=12345 echo "$cnt" echo "${cnt}" echo "${cnt}67890abcd" int_a=6666 abcd="hello" float_c=123.456 char_d='A' printf "%d,%f,%c,%s\n" $int_a $float_c $char_d $abcd4. 获取命令行传递的参数#!/bin/bash printf "脚本名称:$0\n" printf "第一个参数:$1\n" printf "第二个参数:$2\n" printf "第三个参数:$3\n" printf "所有参数:$*\n" printf "参数总个数:$#\n" rm 123.c printf "上一个命令执行状态:Öb63ca76-b51b-4b18-b215-c16480aab05dn" $?5. 算术运算符#!/bin/bash a=10 b=20 c=30 d=`expr $a + $b + $c` printf "d=$d\n" d=`expr $a \* $b` printf "d=$d\n" d=`expr $a '*' $b` printf "d=$d\n" d=`expr \( 12 + 66 + 77 \) \* 12` printf "d=$d\n"6. if语句基本用法基本语法格式: #!/bin/bash if [ 123 -eq 123 ] then printf "相等\n" fi if [ 123 -eq 456 ] then printf "相等\n" else printf "不相等\n" fi if [ 123 -eq 456 ] then printf "123 -eq 456 相等\n" elif [ 456 -eq 888 ] then printf "456 -eq 888 相等\n" elif [ 456 -eq 456 ] then printf "456 -eq 456 相等\n" else printf "123 -eq 456 不相等\n" fi if [ 123 -eq 123 -a 456 -eq 456 ] then printf "相等1\n" fi if [ 123 -eq 123 -o 456 -eq 457 ] then printf "相等2\n" fi if [ 123 -eq 123 -o 456 -eq 457 ] && [ 123 -eq 123 -a 456 -eq 457 ] then printf "相等3\n" fi if [ 123 -eq 123 -o 456 -eq 457 ] || [ 123 -eq 123 -a 456 -eq 457 ] then printf "相等4\n" fi7. 如何从键盘上输入数据?#!/bin/bash read -p "请输入一个整数:" data printf "你输入的整数:Öb63ca76-b51b-4b18-b215-c16480aab05dn" ${data} printf "请输入一个浮点数:" read f_data printf "你输入的浮点数:öb63ca76-b51b-4b18-b215-c16480aab05dn" ${f_data} read -t 3 -p "输入一个字符串:" str_data if [ $? -eq 0 ] then printf "你输入的字符串:%s\n" $str_data else printf "你输入太慢了.\n" fi read -s -p "请输入密码:" pass printf "你输入的密码:%s\n" $pass8. 判断平年和闰年#!/bin/bash read -p "请输入年份:" year #1. 能被4整除 并且不能被100整除 #2. 能被400整除 if [ `expr $year % 4` -eq 0 -a `expr $year % 100` -ne 0 ] || [ `expr $year % 400` -eq 0 ] then printf "%d 是闰年.\n" $year else printf "%d 是平年.\n" $year fi if [ `expr $year % 4` -eq 0 -a `expr $year % 100` -ne 0 ] then printf "%d 是闰年.\n" $year elif [ `expr $year % 400` -eq 0 ] then printf "%d 是闰年.\n" $year else printf "%d 是平年.\n" $year fi9. for循环的基本使用#!/bin/bash for data in 1 2 3 4 5 6 7 9 0 do if [ $data -eq 5 ] then break 1 fi printf "data1=Öb63ca76-b51b-4b18-b215-c16480aab05dn" $data done for data in 1 2 3 4 5 6 7 9 0 do if [ $data -eq 5 ] then continue fi printf "data2=Öb63ca76-b51b-4b18-b215-c16480aab05dn" $data done for file_name in *.sh do printf "file_name=%s\n" $file_name done for file_name in /home/wbyq/*.sh do printf "file_name=%s\n" $file_name done10. 使用for循环输出9*9乘法口诀表#!/bin/bash for i in 1 2 3 4 5 6 7 8 9 do for j in 1 2 3 4 5 6 7 8 9 do printf "%d*%d=%d " $j $i `expr $i '*' $j` if [ $i -eq $j ] then break 1 fi done printf "\n" done [wbyq@wbyq linux_c]$ ./shell.sh 1*1=1 1*2=2 2*2=4 1*3=3 2*3=6 3*3=9 1*4=4 2*4=8 3*4=12 4*4=16 1*5=5 2*5=10 3*5=15 4*5=20 5*5=25 1*6=6 2*6=12 3*6=18 4*6=24 5*6=30 6*6=36 1*7=7 2*7=14 3*7=21 4*7=28 5*7=35 6*7=42 7*7=49 1*8=8 2*8=16 3*8=24 4*8=32 5*8=40 6*8=48 7*8=56 8*8=64 1*9=9 2*9=18 3*9=27 4*9=36 5*9=45 6*9=54 7*9=63 8*9=72 9*9=81 11. while 循环基本用法#!/bin/bash #无限循环的编写案例 #while : #do # printf "hello\n" # sleep 1 #done #常规用法 cnt=0 while [ $cnt -lt 10 ] do printf "cnt=Öb63ca76-b51b-4b18-b215-c16480aab05dn" $cnt cnt=`expr $cnt + 1` done12. 使用while循环输出9*9乘法口诀表#!/bin/bash i=1 while [ $i -lt 10 ] do j=1 while [ $j -le $i ] do printf "%d*%d=%d " $j $i `expr $j \* $i` j=`expr $j + 1` done printf "\n" i=`expr $i + 1` done [wbyq@wbyq linux_c]$ ./shell.sh 1*1=1 1*2=2 2*2=4 1*3=3 2*3=6 3*3=9 1*4=4 2*4=8 3*4=12 4*4=16 1*5=5 2*5=10 3*5=15 4*5=20 5*5=25 1*6=6 2*6=12 3*6=18 4*6=24 5*6=30 6*6=36 1*7=7 2*7=14 3*7=21 4*7=28 5*7=35 6*7=42 7*7=49 1*8=8 2*8=16 3*8=24 4*8=32 5*8=40 6*8=48 7*8=56 8*8=64 1*9=9 2*9=18 3*9=27 4*9=36 5*9=45 6*9=54 7*9=63 8*9=72 9*9=81
  • [技术干货] IOT开发基础知识系列--Linux(pthread)线程通信(自旋锁)
    1. 自旋锁介绍自旋锁不管是内核编程,还是应用层编程都会用到;自旋锁和互斥量类似,它不是通过休眠使进程阻塞,而是在获取锁之前一直处于忙等(也就叫自旋)状态。自旋锁可用于下面的情况:锁被持有的时间短,并且线程不希望再重新调度上花费太多的成本。自旋锁通常作为底层原语用于实现其他类型的锁。根据他们所基于的系统架构,可以通过使用测试并设置指令有效地实现。当然这里说的有效也还是会导致CPU资源的浪费:当线程自旋锁变为可用时,CPU不能做其他任何事情,这也是自旋锁只能够被只有一小段时间的原因。自旋锁总结:自旋锁和互斥锁的使用框架、场景相似的。互斥锁在得不到锁的时候会休眠。自旋锁在得不到锁的时候不会休眠,会一直检测锁的状态。自旋锁比较适合保护变量赋值、函数调用等场景。2. 自旋锁相关接口函数1. 销毁自旋锁 int pthread_spin_destroy(pthread_spinlock_t *); 2. 初始化自旋锁 int pthread_spin_init(pthread_spinlock_t *, int); 3. 自旋锁上锁(阻塞) int pthread_spin_lock(pthread_spinlock_t *); 4. 自旋锁上锁(非阻塞) int pthread_spin_trylock(pthread_spinlock_t *); 5. 自旋锁解锁 int pthread_spin_unlock(pthread_spinlock_t *); 以上函数成功都返回0.pthread_spin_init 函数的pshared参数表示进程共享属性,表明自旋锁是如何获取的,如果它设为PTHREAD_PROCESS_SHARED,则自旋锁能被,可以访问锁底层内存的线程所获取,即使那些线程属于不同的进程。否则pshared参数设为PTHREAD_PROCESS_PRIVATE,自旋锁就只能被初始化该锁的进程内部的线程访问到。如果自旋锁当前在解锁状态,pthread_spin_lock函数不要自旋就可以对它加锁,试图对没有加锁的自旋锁进行解锁,结果是未定义的。需要注意,不要在持有自旋锁情况下可能会进入休眠状态的函数,如果调用了这些函数,会浪费CPU资源,其他线程需要获取自旋锁需要等待的时间更长了。3. 自旋锁运用模板下面代码创建了两个线程,分别访问一个全局变量,这里采用自旋锁进行保护。#include <stdio.h> #include <unistd.h> #include <string.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <dirent.h> #include <stdlib.h> #include <pthread.h> pthread_spinlock_t spinlock; int data; /* 线程工作函数 */ void *thread_work_func(void *dev) { while(1) { pthread_spin_lock(&spinlock); //上锁 printf("data=Ó7ca21be-0233-4f37-8100-aa18966f694bn",data); pthread_spin_unlock(&spinlock); //解锁 sleep(1); } } /* 线程工作函数 */ void *thread_work_func2(void *dev) { while(1) { pthread_spin_lock(&spinlock); //上锁 data++; pthread_spin_unlock(&spinlock); //解锁 sleep(1); } } int main(int argc,char **argv) { //初始化自旋锁 pthread_spin_init(&spinlock,PTHREAD_PROCESS_PRIVATE); /*1. 创建子线程1*/ pthread_t thread_id; if(pthread_create(&thread_id,NULL,thread_work_func,NULL)!=0) { printf("子线程1创建失败.\n"); return -1; } /*2. 创建子线程2*/ pthread_t thread_id2; if(pthread_create(&thread_id2,NULL,thread_work_func2,NULL)!=0) { printf("子线程2创建失败.\n"); return -1; } /*3. 等待线程的介绍*/ pthread_join(thread_id,NULL); pthread_join(thread_id2,NULL); //销毁自旋锁 pthread_spin_destroy(&spinlock); return 0; }
总条数:90 到第
上滑加载中