C语言软件编程经验交流.ppt

上传人:牧羊曲112 文档编号:5426556 上传时间:2023-07-05 格式:PPT 页数:68 大小:920.50KB
返回 下载 相关 举报
C语言软件编程经验交流.ppt_第1页
第1页 / 共68页
C语言软件编程经验交流.ppt_第2页
第2页 / 共68页
C语言软件编程经验交流.ppt_第3页
第3页 / 共68页
C语言软件编程经验交流.ppt_第4页
第4页 / 共68页
C语言软件编程经验交流.ppt_第5页
第5页 / 共68页
点击查看更多>>
资源描述

《C语言软件编程经验交流.ppt》由会员分享,可在线阅读,更多相关《C语言软件编程经验交流.ppt(68页珍藏版)》请在三一办公上搜索。

1、报告人:吴宪云,C语言软件编程之经验交流,西安电子科技大学,这次报告比较局限于 C 语言,不会讲太多其他高级语言比如 C+,JAVA,PYTHON 等等,刚进实验室的学生我的建议是先学好 C 语言,掌握项目开发中软件的开发目的,开发流程,测试流程等。注意,做这个报告的目的是希望大家能够开发出高效的 C 程序,而不是让大家开发出复杂高难度高技巧的 C 程序。,报告目的,提纲,一、C 语言基础二、内存管理三、常用技巧四、调试五、示例,开发软件,工欲善其事,必先利其器-论语牢牢打好基础,紧紧抓住核心,真正实现目的-深入学习科学发展观,编辑软件:VC+6.0,VS20XX编程辅助软件:msdn功能性辅

2、助软件:vc assistant,numega bounds checker,intelvtune,source insight推荐的资料:高质量 C/C+编程指南(林锐)、Windows 核心编程、linux 高级程序设计,一、C语言基础,在 C 语言中使用的词汇分为六类:标识符,关键字,运算符,分隔符,常量,注释符。,1.1.1 C 语言词汇,标识符只能是字母、数字、下划线组成的字符串,并且其第一个字符必须是字母或下划线。以下标识符是合法的:a,x,_3x,BOOK_1,sum5以下标识符是非法的:3s 以数字开头;s*T 出现非法字符*;-3x 以减号开头;,(1)标识符,一、C语言基础

3、,在使用标识符时注意以下几点:标准 C 不限制标识符的长度,但它受各种版本的 C 语言编译系统限制,同时也受到具体机器的限制;在标识符中,大小写是有区别的。例如 BOOK 和 book 是两个不同的标识符;标识符虽然可由程序员随意定义,但标识符是用于标识某个量的符号。因此,命名应尽量有相应的意义,以便阅读理解,作到“顾名思义”。int ImgWidth;,(1)标识符,一、C语言基础,1、匈牙利命名法:开头字母用变量类型的缩写,其余部分用变量的英文或英文的缩写,要求单词第一个字母大写。int iMyAge;“i”是int类型的缩写;char cMyName10;“c”是char类型的缩写;fl

4、oat fManHeight;“f”是float类型的缩写;2、驼峰规则:又叫小驼峰式命名法。第一个单词首字母小写,后面其他单词首字母大写。int myAge;char myName10;float manHeight;3.帕斯卡命名法:又叫大驼峰式命名法。每个单词的第一个字母都大写。int MyAge;char MyName10;float ManHeight;,一、C语言基础,关键字是由 语言规定的具有特定意义的字符串,通常也称为保留字。用户定义的标识符不应与关键字相同。C 语言的关键字分为以下几类:,(2)关键字,一、C语言基础,类型说明符 用于定义、说明变量、函数或其它数据结构的类型。

5、如 char,short,int,double 等语句定义符 用于表示一个语句的功能。如 for,if,else,while,switch 等。预处理命令字 用于表示一个预处理命令。如#define#pragma 等。,C 语言中运算符与变量,函数一起组成表达式,表示各种运算功能。运算符由一个或多个字符组成,如,=,&等。,(3)运算符,(4)分隔符,在 C 语言中采用的分隔符有逗号和空格两种。,一、C语言基础,(5)常量,C 语言中使用的常量可分为数字常量、字符常量、字符串常量、符号常量、转义字符等多种。比如 char*p=“hello world”;C 语言中的常量是不接受程序修改的固定值

6、。,(6)注释符,C 语言的注释符是以“/*”开头并以“*/”结尾的串,C+中使用“/”注释所在行。,一、C语言基础,什么是字节对齐,为什么要字节对齐?,1.1.2 字节对齐,一、C语言基础,(1)什么是字节对齐?,现代计算机中内存空间都是按照 byte 划分的,从理论上讲对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定变量的时候经常在特定的内存地址访问,这就需要各类型数据按照一定的规则在空间上排列,而不是顺序的一个接一个的排放,这就是对齐。,一、C语言基础,(2)为什么要字节对齐?,对齐的作用和原因:各个硬件平台对存储空间的处理上有很大的不同。一些平台对某些特定类型的数据只能

7、从某些特定地址开始存取。其他平台可能没有这种情况,但是最常见的是如果不按照适合其平台的要求对数据存放进行对齐,会在存取效率上带来损失。比如有些平台每次读都是从偶地址开始,如果一个 int型(假设为 32 位)如果存放在偶地址开始的地方,那么一个读周期就可以读出,而如果存放在奇地址开始的地方,就可能会需要 2 个读周期,并对两次读出的结果的高低 字节进行拼凑才能得到该int数据。,一、C语言基础,(3)大小端(例程),在计算机系统中,我们是以字节为单位的,每个地址单元都对应着一个字节,一个字节为 8bit。对于位数大于 8 位的处理器,由于寄存器宽度大于一个字节,那么必然存在着一个如何将多个字节

8、安排的问题。,所谓的大端模式,是指数据的低位保存在内存的高地址中,而数据的高位,保存在内存的低地址中;所谓的小端模式,是指数据的低位保存在内存的低地址中,而数据的高位保存在内存的高地址中,一、C语言基础,(3)大小端(例程),写一个 C 函数,若处理器是 Big_endian 的,则返回 0;若是 Little_endian的,则返回 1,int checkCPU()union w int a;char b;c;c.a=1;return(c.b=1);,一、C语言基础,(3)大小端(例程),采用 Little-endian 模式的 CPU 对操作数的存放方式是从低字节到高字节,而 Big-en

9、dian 模式对操作数的存放方式是从高字节到低字节序是所有成员都从低地址开始存放。联合体 union 的存放顺序是所有成员都从低地址开始存放。,一、C语言基础,/作者版权版本说明,头文件声明,全局变量,函数声明,预处理块#include#include”global.h”void output();/子函数声明int main(int argc,char*argv)int i,j;unsigned char*data;/定义局部变量/分配数据空间,分配在堆上data=(unsigned char*)malloc(1000*sizeof(unsigned char);for(i)/调用子函数ou

10、tput();/释放分配空间free(data);data=NULL;void output(),一、C语言基础,#ifndef GRAPHICS_H(作用:防止graphics.h被重复引用)#define GRAPHICS_H#include.(作用:引用标准库的头文件)#include.(作用:引用非标准库的头文件)void Function1(.);(作用:全局函数声明)class Box(作用:类结构声明);#endif,1.2.1 头文件,一、C语言基础,在头文件中,用 ifndef/define/endif结构产生预处理块,用#include 格式来引用库的头文件。头文件一般由三

11、部分内容组成:,1.2.1 头文件,头文件开头处的版权和版本声明;预处理块;函数和类结构声明等。,一、C语言基础,头文件的主要作用在于调用库功能,对各个被调用函数给出一个描述,其本身不包含程序的逻辑实现代码,它只起描述性作用,告诉应用程序通过相应途径寻找相应功能函数的真正逻辑实现代码。用户程序只需要按照头文件中的接口声明来调用库功能,编译器会从库中提取相应的代码。,1.2.1 头文件,一、C语言基础,注意:1)在.h文件中声明的函数,如果在其对应的.c 文件中有定义,那么我们在声明这个函数时,不使用 extern 修饰符,如果反之,则必须显示使用 extern 修饰符;2)不要在.h 文件中编

12、写实现代码,不要#include“.c”文件。,1.2.1 头文件,一、C语言基础,所有全局变量尽量以 g_ 开头,并且尽可能声明成 static 类型;尽量杜绝跨文件访问全局变量.如果的确需要在多个文件内访问同一变量,应该由该变量定义所在文件内提供 GET/PUT 函数实现;全局变量必须要有一个初始值,全局变量尽量放在一个专门的函数内初始化;如调用全局变量的函数少于三个,考虑改为局部变量实现。,1.2.2 谨慎使用全局变量,一、C语言基础,在实际的软件项目中,每个人负责的可能只是一个模块,对全局变量的使用没有小程序那样简单,在使用全局变量的时候更要谨慎,跨模块调用的全局变量使用时都需要申请,

13、而且定义必须明确。,1.2.2 谨慎使用全局变量,一、C语言基础,void main(int argc,char*argv),1.2.3 main函数,一、C语言基础,命令行界面的程序,通常都需要输入命令行参数帮助程序执行。假定有一个可执行程序名为 test.exe。运行该程序的的命令行如下:test.exe带命令行参数是同一行中的附加项:test.exe c TEST其中 c 和 TEST 就是命令行参数。C程序通过使用 main()的参数来读取这些附加参数。,main(int argc,char*argv)这个函数中两个参数的意义:argc 记录的是命令行中输入参数的数目;argv 是一个

14、拥有 argc 个元素的字符串数组,每个元素保存一个命令行中输入的参数。,1.2.3 main函数,一、C语言基础,#include int main(int argc,char*argv)int i;for(i=0;i argc;i+)printf(Argument%d is%s.n,i,argvi);return 0;,1.2.3 main函数,一、C语言基础,下面的程序演示 argc 和 argv 的使用:,Argument 0 is hello.exe.Argument 1 is a.Argument 2 is b.Argument 3 is c.Argument 4 is d.Arg

15、ument 5 is e.,1.2.3 main函数,一、C语言基础,运行结果:,假如上述代码编译为 hello.exe,那么运行:hello.exe a b c d e,1.2.3 main 函数,一、C语言基础,在这个例子中,argc 的值为 6,命令行一共输入了六个参数:“hello.exe”、“a”、“b”、“c”、“d”、“e”对应程序输入为:argv0:repeat.exe,argv1:a,argv2:b,argv3:c,argv4:d argv5:e,需要注意的是若输入参数作为数值使用时,使用 atoi atof进行字符转换 看例程,一、C语言基础,1.3 代码编写规范,从书写清

16、晰,便于阅读,理解,维护的角度出发,在书写程序时应遵循以下规则:,一个说明或一个语句占一行。if,for,while,do占一行,执行语句放后面并且使用大括号,多用对齐。用 括起来的部分,通常表示了程序的某一层次结构。一般与该结构语句的第一个字母对齐,并单独占一行。低一层次的语句或说明可比高一层次的语句或说明缩进若干格后书写。以便看起来更加清晰,增加程序的可读性。在编程时应力求遵循这些规则,以养成良好的编程风格。多写注释,合理的使用注释可以让你的程序可读性更高。,一、C语言基础,另外一些编程风格说明:,程序块要采用缩进风格编写,缩进少使用空格键;对齐多使用TAB键,少使用空格键;逗号、分号只在

17、后面加空格。int a,b,c;比较操作符,赋值操作符“=”,“+=”,算术操作符“+”,“%”,逻辑操作符“&”,“&”,位域操作符“”,“”等双目操作符的前后加空格;,一、C语言基础,另外一些编程风格说明:,“!”,“”,“+”,“-”,“/“-”指针前后不加空格 if、for、while、switch等与后面的括号间应加空格,使if等关键字更为突出、明显。if(a=b&c d),一、C语言基础,一、C语言基础,1.4 命名规则,使用匈牙利命名法,标识符应直观意思明确尽量使用缩写,如 int iImgWidth;不要使用大小写来区分变量,如 int x,X;局部变量不要与全局变量同名;常量

18、使用大写字母,合理使用前缀,静态变量加前缀s_,全局变量加前缀 g_。,一、C语言基础,1.5 表达式,注意优先级的的高低以及结合顺序,多使用括号确定优先级,一、C语言基础,1.5 表达式,注意if常用的条件判断情况:布尔变量 if(flag)if(!flag)整型变量 if(flag=0)if(flag!=0)浮点变量 if(abs(x-0)1e-5)指针变量 if(p=NULL)if(p!=NULL),if 语句,一、C语言基础,1.5 表达式,注意以下几点:多重循环中,尽量将循环少的放在外层循环for(i=0;iN;i+),循环执行 N 次,最大执行到 i=N-1,i最后执行完等于Nsw

19、itch 的每个 case 都加上 break,最后加上 default尽量少用 goto,循环语句,从静态存储区域分配,在程序编译的时候就已经分配好,整个运行期都存在。如全局变量和 static 变量。从栈上创建,从函数创建开始存在,函数结束就释放,效率高,但是分配大小有限。如函数内部变量。从堆上分配,也称动态内存分配。使用 malloc 分配,需要手动 free 释放。使用灵活,容易出问题。,C语言中内存分配区域:,二、内存管理,二、内存管理,2.1 常见内存错误,没有分配直接使用或者分配未成功却使用了它;没有初始化或者归零就直接使用(分配内存后系统默认值不一定是 0);使用时内存访问越界

20、,使用完忘记释放内存,造成内存泄漏;对已分配内存的指针进行赋值操作,原来分配内存区域丢失,内存泄漏;释放了内存却继续使用,指针在释放后并不是变为 NULL,仍然指向原来地址,成为“野指针”。,二、内存管理,2.2 指针与数组,数组在栈上和静态存储区域创建,其地址与容量分配后不可改变,但内容可以改变;指针的特征是“可变”,用于分配动态内存区域;不能直接对数组名进行复制和比较,使用 strcpy 和 strcmp;指针存储的是动态内存区域的地址,可以直接传递地址,当对两块动态内存区域复制或比较时使用memcpy 和 memcmp;数组的大小,需要加上最后面的0,可以使用 sizeof 获得;指针使

21、用 sizeof 获得的是指针变量的字节数;需要注意的是当数组作为函数参数传递时,自动退化为该类型的指针。,二、内存管理,2.2 指针与数组,例子:,二、内存管理,2.3 指针,指针的本质是地址,指针变量本身作为普通寄存器变量被存储,特别是该寄存器地址内存储的是另一个寄存器地址,该寄存器地址内存储的数据是指针指向的数据。,栈,main,int i=200;,char*p;,0 x123456,假设已给p分配空间0 x12 3456p=0 x123456i=200,0 x123456,0 x123452,100,*p=100,0 x201212,0 x201216,&p=0 x201216&i=

22、0 x201220,200,栈,二、内存管理,2.3 指针,malloc 在堆上分配动态内存区域,需要指定分配区域的大小,以字节作为单位。,p=(char*)malloc(1*sizeof(char);/分配到0 x123456,存储在栈地址0 x201216的内存地址中*p=100;/修改0 x123456中数值为100/free将分配的动态内存区域释放free(p);/虽然0 x123456该地址被标志为已释放,但是p内存储的仍然是 0 x123456,p成为野指针p=NULL;/将0 x201216内数据改为0 x00,该地址不可访问,malloc 与 free:,二、内存管理,当子函数

23、中使用指针时,子函数执行结束指针没有 free 掉,此时指针变量释放了,不代表它所指向的内存自动释放了。当内存被释放时,不代表指针不存在了或者指针成为 NULL 指针。需要查找程序内存泄漏。,2.3 指针,需要注意的几点:,三、常用技巧,3.1 宏的使用,#define ceil_div(x,y)(x+y-1)/y,宏执行的是简单的替换作用,需要注意由操作符优先级引起的问题,多加括号。,那么 a=ceil_div(b 为了避免这种情况发生,应当多写几个括号:#define ceil_div(x,y)(x)+(y)-1)/(y),三、常用技巧,3.1 宏的使用,函数变宏,每行代码最后都加行连接符

24、“”,即使是空行也要加“”,最后一行代码后面不需要加“”,每行“”最后不能有多余字符或者空格,返回的是最后一条语句的执行结果。可以在宏函数内定义变量,可以使用if等语句,可以在宏内调用其他宏,可以使用指针。函数变宏可以加快程序运行速度。看例子,三、常用技巧,3.2 运行时间测量,程序运行过程中,我们经常需要统计程序运行时间。下面给出示例:,#include main()clock_t begin,end;begin=clock();end=clock();double duration;duration=(double)(end-begin)/CLOCKS_PER_SEC;printf(“Ti

25、me is%2.1f secondsn,duration);/#define CLOCKS_PER_SEC 1000/事实上end begin获得的是毫秒计数,三、常用技巧,3.2 运行时间测量,Time()函数是获得当前系统时间用的,一般不用于计时。当程序运行时间太短时,可以使用多次执行的办法来获得。可以使用更精确的运行时间计数函数:“QueryPerformanceCounter()”“QueryPerformanceFrequency()”,三、常用技巧,随机数生成:,#include#include#include void main(void)int i;/*Seed the ran

26、dom-number generator with current time so that*the numbers will be different every time we run.*/srand(unsigned)time(NULL);/*Display 10 numbers.*/for(i=0;i 10;i+)printf(%6dn,rand();,Srand是产生伪随机序列的种子,种子一样产生的伪随机序列一样。RAND_MAX0 x7fffffff j=(int)(*rand()/(RAND_MAX+1.0)产生一个0到之间的随机数,三、常用技巧,3.3 文件操作,文件的打开与关

27、闭 文件在进行读写操作之前要先打开,使用完毕要关闭。打开文件实际上是建立文件的各种有关信息,并使文件指针指向该文件,以便进行其它操作。关闭文件则断开指针与文件之间的联系,也就禁止再对该文进行操作。在语言中,文件操作都是由库函数来完成的。fp=fopen(“filename”,“r”);,三、常用技巧,对于文件使用方式有以下几点说明:文件使用方式由r,w,a,b,t,+六个字符拼成,各字符的含义是:r(read):读 w(write):写 a(append):追加 b(binary):二进制文件+:读和写 凡用“r”打开一个文件时,该文件必须已经存在,且只能从该文件读出。用“w”打开的文件只能向

28、该文件写入。若打开的文件不存在,则以指定的文件名建立该文件,若打开的文件已经存在,则将该文件删去,重建一个新文件。,三、常用技巧,if(fp=fopen(“readme.txt,rb)=NULL)printf(nerror on open c:hzk16 file!);exit(1);,若要向一个已存在的文件追加新的信息,只能用“a”方式打开文件。但此时该文件必须是存在的,否则将会出错。在打开一个文件时,如果出错,fopen将返回一个空指针值NULL。在程序中可以用这一信息来判别是否完成打开文件的工作,并作相应的处理。,三、常用技巧,文件的读写对文件的读和写是最常用的文件操作。在语言中提供了多

29、种文件读写的函数:字符读写函数:fgetc和fputc 字符串读写函数:fgets和fputs 数据块读写函数:fread和fwrite 格式化读写函数:fscanf和fprinf行操作。,三、常用技巧,文件的读写在文件内部有一个位置指针,用来指向文件的当前读写字节。在文件打开时,该指针总是指向文件的第一个字节。使用fgetc 函数后,该位置指针将向后移动一个字节。应注意文件指针和文件内部的位置指针不是一回事。文件指针是指向整个文件的,文件内部的位置指针用以指示文件内部的当前读写位置,每读写一次,该指针系统自动向后移动。,三、常用技巧,计算文件长度的程序示例,long filesize(FIL

30、E*stream)long curpos,length;curpos=ftell(stream);fseek(stream,0L,SEEK_END);length=ftell(stream);fseek(stream,curpos,SEEK_SET);return length;,进行二进制文件读写时,打开方式后面加“b”,四、调试,编程出现error时,从第一个error处开始解决错误,可能是很小的书写错误引起的。warning也需要关注,有时候会导致程序运行错误发生。程序出现BUG时,单步跟踪,查看变量,查看内存,查看栈调用,可以边编辑边跟踪。加入合适的断点,使用条件断点。程序调试结束后需

31、要查找内存泄露,规范代码书写。使用assert,只有条件满足才继续向下执行,在release下不会编译该语句。,程序编写完成不一定是完全正确的,需要进行测试并进行跟踪调试。,四、调试,4.1 条件断点,我们在调试的时候希望程序在某个断点处只有在满足一定的条件下中断,在不满足条件的时候正常运行,可以为程序调试带来极大的便利。示例,四、调试,4.2 内存泄漏查找,养成好的代码写作规范,掌握内存管理概念,减少不规范代码内存泄漏可能性。是否内存泄露:运行可执行文件,使用任务管理器查看内存占用情况是否一直增加。比较简单但是显示不一定精确。使用NumegaBounderChecker软件查找,程序中加入e

32、xit(0)强制中断,Debug至该代码行程序异常中断时查看内存泄露报告。示例,四、调试,4.3 watch,跟踪调试时多使用watch窗口,在watch窗口内可以进行有限运算,注意watch 运算带来的影响。示例,四、调试,4.4 C 程序优化,首先要确定优化目标,然后寻找优化方法。查找程序运行瓶颈,使用Intel Vtune查看各部分运行时间,一步步进行优化。现在CPU,GPU发展方向都是多核,并行计算越来越方便,为优化提供了更多解决方案。,任务级并行,使用多线程发挥多核优势。指令级并行,使用MMX,SSE,SSE2等指令集。参看Vtune使用指南,五、示例,5.1 软件设计,算法思想,思

33、路清楚,注意细节质量控制,代码高效,风格良好测试调试,测试全面,调试认真,软件设计过程关键部分:,在编写软件程序之前,首先要明确你要解决的问题,软件只是思想的实现,不能通过编程来获得思想。所以在编写之前就需要对问题有透彻的理解,对解决问题的方法有清晰的思路,要考虑到可能遇到的所有问题,同时要考虑到软件的可靠性稳定性等。,五、示例,5.1 软件设计,在编写软件程序之前,首先要明确你要解决的问题,软件只是思想的实现,不能通过编程来获得思想。所以在编写之前就需要对问题有透彻的理解,对解决问题的方法有清晰的思路,要考虑到可能遇到的所有问题,同时要考虑到软件的可靠性稳定性等。在代码编写的时候,注意代码编

34、写规范,编写风格良好的代码,多用注释让代码的可读性变高。实际上一个项目中代码编写的时间可能是最短的。前期算法的测试和后期测试工作占得时间更多。代码编译通过不代表软件完成,代码编写完成后需要进行大量的测试来确保程序的正确性,这也要求代码编写的适合大规模测试。在遇到问题的时候首先思考下算法设计是否合理,重新考虑下软件编写思路是否还有没有考虑到的情况,然后对代码进行跟踪调试。,五、示例,5.2 VC6+的使用,创建程序添加程序文件编写代码编译运行设置参数调试程序,五、示例,5.3 例子一(看示例),蒙塔卡罗算法计算圆周率,以概率和统计理论方法为基础的一种计算方法。将所求解的问题同一定的概率模型相联系

35、,用计算机实现统计模拟或抽样,以获得问题的近似解。,利用求圆的的面积来求得 Pi。在正方形中随机投入很多点,使所投的点落在正方形中每一个位置的机会相等看其中有多少个点落在圆内。将落在圆内的点数 m 与所投点的总数 n 的比 m/n 作为理论值的近似值。,问题描述,思路,软件设计过程,先产生随机数据,判断该数据是否落在圆内,统计落在圆内的点数。最后计算圆周率。,五、示例,5.3 例子二(看示例),动态链接的好处,扩展了应用程序的特性,可以用许多种编程语言来编写;简化了软件项目的管理;有助于节省内存,有助于资源共享;有助于应用程序的本地化,有助于解决平台差异;可以用于一些特殊的目的。windows

36、使得某些特性只能为DLL所用。保护了代码版权。,VC+6.0中使用动态链接库封装程序,在vs2005中,在项目属性中配置输出为动态链接库。(参看我的教程),五、示例,5.3 例子三(看示例),多线程编程,首先要明确线程的概念(参考windows核心编程),windows中多线程并不是物理上的并行(单核CPU),而是通过CPU的时分复用来实现多线程的并行计算。多线程中的调试是非常麻烦的,因此在设计的时候就先要考虑清楚设计思路。多线程中经常发生资源共享冲突,为了保证多个进程互斥地对共享资源进行访问,一般使用互斥体(mutex)、临界量(critical_section)、事件(event)和信号量(semaphore)来解决。互斥体和临界量每次只准许一个线程对共享资源进行访问,不允许其他线程同时访问。信号量每次允许有限个线程对共享资源进行访问,超过限制的则进行等待。事件可以手动控制线程进行访问。,五、示例,5.3 例子三(看示例),多线程编程,比如ATM机。如果只有一台ATM机,我们可以使用互斥体和临界量来协调使用,获得互斥体访问权的或者临界量优先权的先使用ATM,使用完后给其他人使用。信号量则对应的是多台ATM机的情形,假设共有三台ATM机,则每次最多可以有三个线程进行访问,其余的只能等待。,谢谢大家!,欢迎交流:,

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 生活休闲 > 在线阅读


备案号:宁ICP备20000045号-2

经营许可证:宁B2-20210002

宁公网安备 64010402000987号