智能车编程总结

2024-08-25

智能车编程总结(通用9篇)

智能车编程总结 篇1

智能车编程总结

智能车核心是飞思卡尔xs128芯片,尽可能利用单片机里的硬件资源是程序的核心。程序理应要有漂亮的算法,但由于智能车任务不复杂,合理管理和配置硬件资源才是最重要的。 编程步骤(关键找到程序框架)

I.程序第一步:通过配置寄存器来编写单片机资源的底层程序。

A.配置总线时钟频率(通过锁相环电路)

B.配置输出PWM(脉宽调制波)功能(占空比)

C.配置定时中断功能(PIT定时中断)

D.配置输入捕捉功能(脉冲累加器)

E.配置基本输入输出端口的电平

II.程序第二步:利用底层程序编写各种其他硬件的驱动程序

A.驱动电机、舵机(通过PWM波)

B.驱动传感器发射和接收(通过IO端口和PWM波)。

C.驱动码盘测速装置并接收。(通过输入捕捉功能)。

III.程序第三步:连接各种硬件,顺序完成巡线任务。

IV.程序第四位:利用控制思想,不断调试和优化程序。

 编程思想(程序关键要清楚)

I.尽量使各种功能都封装成函数。

II.程序分层次,不同层次尽量写在不同文档中(函数层层调用)。

III.主函数中简单明了,思路、层次分明。

IV.各种工具函数同一管理。(延时,绝对值,取最大最小值等)

V.重点参数使用全局变量方便调试。

 控制方法:使用PID控制方法(关键在调试)

I.电机调试PID

(以预设速度与实际检测的速度的差值为偏差值error)

II.摇头舵机PID

(以传感器偏离中心距离为偏差值error)

III.转向舵机PID

(以摇头舵机偏离中心的角度为偏差值error)

其他一些都是根据实际情况的一些细节处理,比如过十字交叉线,出道检测,起点检测等。

智能车竞赛感想(共) 篇2

在几个月的的“飞思卡尔”智能车的制作和研究过程中,从赛道的电源制作、信号检测模块再到小车的主板的制作;从小车可以勉强跑动到尝试各种算法,分析其可行性来让小车得到提速。我们一步一步地走过来,从中学到了不少的知识,总结了不少的经验。在每个阶段中,我们都尽量地将小车改进和完善,争取达到最优效果。

在智能车的制作过程中,我们的小车曾经出现过很多问题,如小车在行驶的中途突然停车,起跑线判断出错,电机驱动烧毁,因为信号微弱经常冲出赛道等问题,或多或少拖慢了我们的进度,但经队员们不断的努力,和指导老师的帮助,我们从硬件和软件上做了一步步的改良和升级,渐渐对各模块有了深入的认识,对整体有了清晰的把握,我们在不断的前进的同时,小车也不断的加速前进。

从小车总体性能各因素考虑,小车系统分为采集、处理、控制三部分。对于采集部分:由于电磁组特点决定了小车的前瞻比较小,而前瞻的大小对速度是有着很大的影响。在这个过程中,我们分析了电感的各种摆放方式对磁场的检测结果。电磁组的传感器的摆放具有比较大的灵活性,这是优点。但对采集回来的信息如何进行有效处理是个难题。由于我们对空间磁场的具体分布的认识不足,也没找到比较好的分析方法,只是运用最简单的左右手法则来确定。这是我们队不足的地方,没有科学的分析方法。关于处理和控制部分:传感器的摆放决定了控制算法。由于没有太多的时间与分析,我们采用的是最简单的摆放方式,但也是很有效的方式,因为信号变化在区间内单调,而双排传感器的摆放能够得到一定的前瞻距离(电磁组的车长度不限)。但长度不是越长越好,太长的话容易在过弯的时候检测到临近的赛道而冲出跑道。在控制算法上,有待尝试多种思路进行比较。当小车行驶较快的时候,机械问题突出,严重影响了小车的运行,制约了小车的提速空间。

捷足智能车出行便捷安全有保障 篇3

近期,我市的公园和街区有不少年轻人开始使用一种新奇的交通工具——捷足智能车。其实捷足智能车可以说不是严格意义上的车,因为它不像传统汽车有车轮和方向盘,而只有一个轮子。尽管造型奇特,但操作简单,驾驶时只需要调整身体的重心就可以改变行驶的速度和方向。目前,市场上的智能车品牌逐渐增多,但是捷足智能车却一直销量领先,是什么原因让这么多的人选择捷足智能车呢?

笔者决定通过亲身体验来找原因,在与捷足智能车的销售人员沟通后,笔者得到了一辆全新捷足智能车一天的免费使用权。经过1-2个小时的练习后,笔者就可以熟练驾驶捷足智能车了,差不多到了上班时间,笔者就驾驶着捷足智能车出门了。市区早高峰依旧是车水马龙,开始笔者还担心捷足智能车比不上汽车的速度,上班可能要迟到了。

可是在经了几个红绿灯之后,笔者心里就很有信心了。因为捷足智能车不需要担心道路拥堵的问题,当很多汽车在拥堵中焦急等待通行时,驾驶着捷足智能车的笔者已经从他们身边潇洒地飞驰而过了。最高25km/h时速的捷足智能车一点也不亚于电动车的速度,笔者到达公司的时间还比以往早到了七八分钟。

下班后按照平时的习惯,笔者驾驶着捷足智能车去超市买食材,从下班路上到超市当然也是一路避开了晚高峰的拥堵,还引来了路人羡慕嫉妒的眼光,有不少年轻人纷纷向笔者询问,这么酷的车在哪里买得到。酷炫的捷足智能车让笔者着实过了一把耍酷的瘾。这么身材小巧的捷足智能车直接驾驶着进去超市或者放到超市购物车里面带进去都可以的,完全不担心停车或者保管的问题。很快笔者就完成了购物,早早地回到了家中。

梦想中的智能车五年级作文 篇4

我梦想中的智能汽车是一辆万能车,只要你登上这辆车,它能满足你全方位的需要,带给你贵宾般的舒适享受。

现在我来介绍一下我的车吧!车子跟现在的`公共汽车差不多大,但里面可用空间很大,家里应有的电器设备它样样俱全。车子是完全智能的,一台主控电脑控制所有设备,你可以跟它说你想去的地方,它会自动设置路线,自动驾驶,不需要你的操作,就可以开到你所需要到达的地方。而你可以在行程内听音乐、上网、看书,喝些饮料等等,如同在家里一样舒适。到达目的地了,它会自动提醒你。

听爸爸说,现在的科技已经很发达了,已经有这样的车了。而我的智能车的功能还有很多,比如我想去海洋潜水,它可以自动收起车轮,变成如潜水艇一样,可以深潜海底。如果我想去天空,它亦会伸展机翼,翱翔蓝天。

智能车编程总结 篇5

一、单项选择题

1.收集来的信息是初始的、零乱的、孤立的信息,对这些信息进行分类和排序,就是信息()。A.发布 B.加工 C.收集 D.获取

2.利用VB程序设计语言进行信息的编程加工的一般顺序是()。

A、设计算法、编写代码、设计界面、调试运行 B、设计算法、编写代码、调试运行、设计界面 C、设计算法、设计界面、编写代码、调试运行 D、编写代码、设计算法、设计界面、调试运行 3.如下算法,是实现()功能的。

(1)输入X,Y(2)如果X>Y,则使MIN的值等于Y的值;否则使MIN的值等于X的值(3)输出MIN的值

A、输入X和Y的值,求X和Y的最小值,并输出最小值 B、输入X和Y的值,求X和Y的最大值,并输出最大值 C、输入X和Y的值,求X和Y的最小值,并输出最大值 4.下列应用中,()不属于人工智能技术应用的范畴?

A、语音识别 B、灭火机器人 C、用表格软件自动统计 D、计算机博弈 5.在Visual Basic中,下列()类型属于字符串型。A.Integer B.Single C.String D.Boolean 6.小华利用电子表格对校运会中的各项比赛成绩进行汇总并排名。请问,这属于信息加工一般过程的()阶段。

A.记录信息 B.加工信息 C.发布信息 D.存储信息

7.读下列程序段,运行该段程序之后,变量a的值是()。a=3;b=4;if a

9.小敏把手指纹对着他家门的微电脑锁上,门就自动打开了,这其中主要应用了人工智能中的()。A.图像识别技术 B.指纹识别技术 C.语音识别技术 D.字符识别技术

10.编制计算机程序解决问题的过程有:描述问题、算法设计、编写计算机程序、调试等,其中,对算法描述不正确的是()。

A、算法是解决问题的步骤集合 B、解题的步骤是有限的 C、算法就是解题的算式

D、算法是可以被表述和实现

二、判断题

11.利用计算机加工信息可以提高信息加工的效率。()

12.Visual Basic 是一种文字处理软件。()13.在EXCEL,OFFICE助手采用了智能代理技术。()

14.利用指纹来鉴定人的身份,可以克服证件、签字、照片、密码、钥匙、印鉴等容易假冒、丢失、遗忘、被盗的缺点。()

15.1997年5月12日,“更深的蓝”之所以能战胜国际象棋之王卡斯帕罗夫,这是因为“更深的蓝”具备了人一样的思维,它比卡斯帕罗夫聪明。()

三、辨析填空(共20分)

16.信息加工有以下几个环节:A.记录信息、B、加工信息、C、发布信息、D、存储信息;请分析以下资料,指出各工作流程分别属于信息加工的哪一个环节,填写于括号里。(8分)

2008年9月16日下午,我校举行了校教职工男女混合4*400接力赛,参加小组有:高一年级组、高二年级组、高三年级组及校工组。裁判员将各小组的比赛成绩记录于规定的参赛项目成绩记录表中,这是信息加工的()环节;然后裁判员再对这些比赛成绩进行分析、排序等工作,排出名次,这又是信息加工的()环节;裁判员将这比赛的结果抄了一份送到广播员处,广播员播出成绩,这属于信息加工的()环节;另将各参赛小组比赛成绩的原材料整理成册送到体卫处存根,这又属于信息加工的()环节。

数控编程总结 篇6

现在我校使用的是GSK928Tc第一章机床数控技术概论,数控是采用数字化信息对机床的运动及其加工过程进行控制的方法。数控控制技术是利用数字化的信息对某一对象进行控制的技术,控制对象可以是为位移、角度、速度等机械量也可是温度、压力、流量、颜色等物理量。数控机床用数字代码的信息,控制刀具按给定的工作程序、运动。

速度和轨迹进行自动加工的机床。按驱动伺服系统类型分类:

1)开环式控制系统的数控机床结构简单,成本较低。但是,系统对移动部件的实际位移量不进行监测,也不进行误差校正;

2)闭环控制数控机床是机床移动部件上直接安装位移直线检测装置,直接对工作台的实际位移进行检测,将测量的实际位移值反馈到数控装置中,与输出的指令位移值进行比较,用差值对机床进行控制,使移动部件按照实际需要的位移量运动,最终实现移动部件的精确运动和定位;

3)半闭环控制数控机床是在伺服电动机的轴或数控机床的传动丝杠装有角位移电流检测装置,通过检测丝杠的转角间接地检测移动部件的实际位移、然后反馈到数控到数控装置中去,并对误差进行修正。

Mudos编程总结[推荐] 篇7

1,Mudos系统调用系统 MudLib系统文件 的过程和一些特点

Mudos启动以后先要寻找一个配置文件,用来配置MudLib文件系统的一些信息(这里时config.cfg),找不到就无法启动。找到以后根据配置文件里面的参数进行初始化Mudos,然后调用配置文件里面的两个入口文件,即simul_efun.c和master.c。首先载入simul_efun文件并生成一个特殊的全局对象,这个对象用于定义一些全局使用的函数,也可以重载Mudos中的Efun函数,这些新定义的文件使用起来和Efun是一样的。然后系统会调用master.c文件并生成一个全局对象(主控对象),主控对象用于系统的全局控制,包括全局对象的加载,错误信息的跟踪处理等。接下来,系统会根据主控对象中的定义,载入一些系统需要用到的全局对象。到此,Mudos系统就启动完成了。

2、用户连接系统后的处理过程。。

当用户通过客户端进行连接以后,Mudos系统会调用master对象特有的connect()函数,通过这个函数编程人员需要创建并返回一个用户对象,系统会将用户连接到这个用户对象上,即是说这个用户对象就代表了这个用户。到此,就算完成了用户的连接过程。

3、用户的登陆后的处理过程

当Mudos系统调用master的connect函数创建并返回一个用户对象以后,用户对象会调用特有的logon()函数,这个函数用来把用户的设置都设置好并进行游戏。注:最好在这里重新建立一个用户对象,然后通过exec函数把用户的连接转移到新的对象上,然后删除这个对象。

4、Mudos系统中的系统中 对象

simul_efun对象、master主控对象和用户对象这三种对象都是系统提供的特殊对象,其 中simul_efun对象和master主控对象在系统中只有一个实例,即不能被clone也不能new创建,而用户对象主要的作用就是用来创建用户并完成初始化的对象,用户每次登陆都会自动生成一个,用户登陆完成后最好删除它。这里需要指出主控对象和用户对象都有特有的一些函数,这些函数提供给Mudos系统来调用的,用来完成一些系统需要处理的事情。

5、Master主控对象

object connect()程序连接后调用的函数,创建并返回一个用户对象。string *epilog(int load_empty)返回一个包含物件文件名称的数组, 其中所有的文件为启动游戏之前必须预先载入的对象.void preload(string file)系统按照epilog函数返回的数组载入全局对象后调用次函数,用来判断对象是否成功创建 static void crash(string error, object command_giver, object current_object)当系统异常终止(crash)时, 就调用主控物件中的此函数,用来记录一些系统crash的log信息。void log_error(string file, string message)编译程序发生任何错误系统都会调用此函数,用于发现是哪个对象出了什么错误。用于记录编译程序时出现的错误信息。

string error_handler(mapping error, int caught)主控物件处理错误的函数,此函数让 mudlib 代替系统处理错误情形。用来处理系统运行时出现的错误信息。string get_root_uid()取得

root 使用者识别名称需要获取系统的uid时调用此函数。string get_bb_uid()取得骨架使用者识别名称。string creator_file(string str)系统创建任何对象时都会调用此函数,用来获得系统初始化对象的uid值。mixed compile_object(string file)提供虚拟对象,当系统无法按照给定的路径载入对象时调用此函数。如果返回值是0,系统将不会载入这个对象,如果返回值是一个对象,系统会把这个对象当作是系统要载入的对象。一般来说,这里会返回一个void对象。string object_name(object ob)系统调用此函数以知晓一个物件的名称。string domain_file(string str)返回一个指定对象所属的区域,系统调用此函数来获得对象的区域。string author_file(string str)返回一个指定对象所属的作者,系统调用此函数来获得对象的作者。int save_ed_setup(object who, int code)ed()函数储存一个使用者的编辑程序设定或组态设定时调用 int retrieve_ed_setup(object who)ed()函数取得使用者的编辑程序设定或组态设定 string make_path_absolute(string file)ed()函数调用此函数以转换文件的相对路径名称为绝对路径名称 string get_save_file_name(string fname)ed()函数使用者不正常断线时, 此函数应返回与原来文件不同的名称, 以免覆写原来的文件 string privs_file(string file)为新创造的对象指定一个私有字符串。创建任何对象时系统都会调用此函数.对象的文件名称为其参数,返回的字符串就用作此对象的私有字符串。void slow_shutdown(int minutes)告知 mud 目前正处于缓慢关闭的过程中.当系统无法从堆中配置更多的内存, 而只能使用保留的内存区块时, 主控物件会调用此函数.此函数只有在组态文件中设定了「内存区块保留大小」才会被调用.距离关闭时间还剩下几分钟则为此函数的参数.void flag(string)当系统启动时, 处理 mudlib 所指定的特定标志.这个函数暂时还不是很了解。int valid_override(string file, string name)是否允许使用 efun:: 的情形,即是否允许运行efun重载前的函数。int valid_seteuid(object ob, string str)是否允许设定一个对象的euid。int valid_socket(object eff_user, string fun, mixed *info)是否允许调用socket 外部函数 int valid_asm(string file)

是否能使用asm{}来控制 LPC->C 编译的物件 int valid_compile_to_c(string file)是否允许由 LPC->C 的方式编译 int valid_hide(object who)是否允许一个对象具有匿踪和看到匿踪对象的能力 int valid_object(object ob)是否允许载入某个对象。int valid_save_binary(string filename)是否允许一个对象储存它的源代码 int valid_bind(object binder, object old_owner, object new_owner)是否允许bind()函数 即把某个对象的函数指针指向其他对象。int valid_write(string file, mixed user, string func)是否允许一个人有权限写入一个文件 int valid_read(string file, mixed user, string func)是否允许一个人有权限读取一个文件 int valid_shadow(object ob)控制哪些对象可以作为投影。int valid_link(string original, string reference)是否允许link()函数 int view_errors(object user)是否允许一个使用者看到错误消息 int valid_compile(string file)是否允许预先编译文件,这是22.2b14新加的设置6、、、、用户对象

void logon()主控对象conncet函数返回的用户对象会直接调用次函数,用以对用户对象的初始化处理。string process_input(string str)用户输入信息后调用此函数,字符串处理后再传递给本用户对象,用来处理用户输入信息。void net_dead()当用户对象断线时, 系统调用此函数。用来处理用户断线后的事情。void terminal_type(string term_type)用户对象登陆后调用,获得用户登陆的终端型号。void receive_message(string type, string str)用户对象的消息处理函数,系统的message()函数会把消息分配给各个符合条件的用户对象,用户对象接收到消息后调用此函数来接收并处理消息。void catch_tell(string message);无论系统对

一个对象送出任何消息都会调用此函数来处理这些消息.消息可以依照需要显示、丢弃、修改.此函数可以当作耳罩挡住某些消息, 也可以用于消息处理程序.void receive_snoop(string message);一个用户对象窥视另一个用户对象时, 所有窥视的文字会传递给用户对象中的这个函数.在此函数中, 您可以处理这些文字.次函数的内容, 通常会再传递给 receive()函数.void telnet_suboption(string buffer);

获得用户终端的一些设置。void write_prompt(void);如果在用户对象中有定义了次函数,则预设的提示符号该显示时, 系统将调用此函数.当用户正处于 input_to(输入文字)和 ed(编辑程序)状态时, 系统不会调用此函数7、、、、所有对象

void create(void);对象的构造函数,对象被系统载入后调用此函数来初始化对象。复制的对象也会调用。需要说明的是,系统第一次载入对象后会自动运行对象和其所有的父类中的create,复制的对象只运行对象自己的create。int id(string an_id);此函数被系统的present()函数调用, 以判断一个指定的对象是否以字符串an_id为识别名称id.如果an_id是此对象的识别名称之一, 就返回 1, 不是则返回 0。void init(void);当系统把对象A放入对象B时(即调用move_object()函数),如果A是人物对象,让A在B里调用A的init函数,同时调用B里面所有对象的init函数。不管A是不是人物对象,让B里所有人物对象调用A的init函数。int move_or_destruct(object dest);如果一个对象的环境对象被摧毁了, 就调用此函数, 并用于它的内容对象.dest是正要被摧毁的对象.如果 dest 不存在, 则 dest 为 0.如果 dest 中的对象没有把自己移出被摧毁的对象, 则也会被一起摧毁.int clean_up(int inherited);系统每过一段时间,对非激活对象调用 clean_up()函数.inherited指出此对象是否有别的对象继承.如果返回 0,此对象将永远不再调用 clean_up().如果返回 1, 则继续判断调用。通常一个对象在 clean_up()中所作的事, 是摧毁自己以节省内存.void reset(void);系统在每次reset之后(时间由系统设定),所有游戏中现存的对象都会调用reset()函数.reset()常用于检查宝物或怪物是否还在某个房间, 以判断要不要重新产生一份.8、、、、一些概念的说明

用户对象用户对象用户对象用户对象((((interactive()):):):):用户连接的对象就是用户对象,系统会调用用户对象的一些方法来实现用户的输入输出和消息处理等。如果用户对象断开连接,用户对象就变成为普通对象。但是系统会记录曾经是用户对象的对象,通过userp()函数可以判断一个对象是否曾经是用户对象。人物人物人物人物对象对象对象对象(living())::::人物对象是曾经呼叫过 enable_commands()的对象,当然用户对象也是人物对象。环境对象环境对象环境对象环境对象(environment())::::环境对象是通过move_object()函数激活的对象。激活激活激活激活对象对象对象对象::::在系统规定的(clear_up)时间内,曾经调用过init()函数的对象。复制复制复制复制对象对象对象对象(clonep())::::系统在第一次载入某个对象后会建立一个初始对象并存于系统内存中,以后每次重新建立对象包括new()、clone_object()、call_other()等都会通过拷贝这个初始对象来建立新的对象,每个拷贝出来的对象,系统都会指定一个递增的数字标识此对象。这里需要说明的是,new()等函数建立对象时,如果初始对象不存在的话,系统会自动载入并初始化此对象,并把此对象定为初始对象,然后再拷贝一个对象作为new()等函数的返回值。系统建立初始对象的时候会由父到子的调用对象所有的create()函数,而拷贝出来的对象只调用对象本身的create()函数。游戏中存在的对象都是复制出来的对象。初始对象只有系统才能调用。

对象对象对象对象uid值值值值::::这个值只能通过主控对象中的creator_file()函数赋值或者export_uid()函数传递。指明当前对象的使用者名称。对象对象对象对象euid值值值值::::对象有效的使用者名称,可以通过seteuid和geteuid函数设置和读取。对象的对象的对象的对象的继承继承继承继承、、、、构造及初始化构造及初始化构造及初始化构造及初始化::::Mudos启动以后,可以自动或者通过函数调用来创建和复制各种对象,Mudos系统的作用就是用来管理这些对象。Mudos在生成对象的时候有两种方式,一种是载入对象,一种是复制已经载入的对象。首先,Mudos是通过对象的文件名来寻找和定位对象的,当需要载入对象的时候,先检查对象是否已经载入,如果没有载入会检查对象是否有需要继承别的对象,如果需要就先载入需要继承的对象,然后再载入并生成需要载入的对象。对象的继承实际上是子对象先浅拷贝一份父对象(但不初始化),然后再构造自己。任何一个对象被载入内存或被复制出来都会执行create函数来初始化自己。9、、、、EFUN函数说明

Java多线程编程总结 篇8

2007-05-17 11:21:59 标签:java 多线程

原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处、作者信息和本声明。否则将追究法律责任。http://lavasoft.blog.51cto.com/62575/27069

Java多线程编程总结

下面是Java线程系列博文的一个编目:

Java线程:概念与原理 Java线程:创建与启动

Java线程:线程栈模型与线程的变量 Java线程:线程状态的转换 Java线程:线程的同步与锁 Java线程:线程的交互 Java线程:线程的调度-休眠 Java线程:线程的调度-优先级 Java线程:线程的调度-让步 Java线程:线程的调度-合并 Java线程:线程的调度-守护线程 Java线程:线程的同步-同步方法 Java线程:线程的同步-同步块

Java线程:并发协作-生产者消费者模型 Java线程:并发协作-死锁 Java线程:volatile关键字 Java线程:新特征-线程池

Java线程:新特征-有返回值的线程 Java线程:新特征-锁(上)Java线程:新特征-锁(下)Java线程:新特征-信号量 Java线程:新特征-阻塞队列 Java线程:新特征-阻塞栈 Java线程:新特征-条件变量 Java线程:新特征-原子量 Java线程:新特征-障碍器 Java线程:大总结

----

下面的内容是很早之前写的,内容不够充实,而且是基于Java1.4的内容,Java5之后,线程并发部分扩展了相当多的内容,因此建议大家看上面的系列文章的内容,与时俱进,跟上Java发展的步伐。----

一、认识多任务、多进程、单线程、多线程 要认识多线程就要从操作系统的原理说起。

以前古老的DOS操作系统(V 6.22)是单任务的,还没有线程的概念,系统在每次只能做一件事情。比如你在copy东西的时候不能rename文件名。为了提高系统的利用效率,采用批处理来批量执行任务。

现在的操作系统都是多任务操作系统,每个运行的任务就是操作系统所做的一件事情,比如你在听歌的同时还在用MSN和好友聊天。听歌和聊天就是两个任务,这个两个任务是“同时”进行的。一个任务一般对应一个进程,也可能包含好几个进程。比如运行的MSN就对应一个MSN的进程,如果你用的是windows系统,你就可以在任务管理器中看到操作系统正在运行的进程信息。

一般来说,当运行一个应用程序的时候,就启动了一个进程,当然有些会启动多个进程。启动进程的时候,操作系统会为进程分配资源,其中最主要的资源是内存空间,因为程序是在内存中运行的。在进程中,有些程序流程块是可以乱序执行的,并且这个代码块可以同时被多次执行。实际上,这样的代码块就是线程体。线程是进程中乱序执行的代码流程。当多个线程同时运行的时候,这样的执行模式成为并发执行。

多线程的目的是为了最大限度的利用CPU资源。

Java编写程序都运行在在Java虚拟机(JVM)中,在JVM的内部,程序的多任务是通过线程来实现的。每用java命令启动一个java应用程序,就会启动一个JVM进程。在同一个JVM进程中,有且只有一个进程,就是它自己。在这个JVM环境中,所有程序代码的运行都是以线程来运行。

一般常见的Java应用程序都是单线程的。比如,用java命令运行一个最简单的HelloWorld的Java应用程序时,就启动了一个JVM进程,JVM找到程序程序的入口点main(),然后运行main()方法,这样就产生了一个线程,这个线程称之为主线程。当main方法结束后,主线程运行完成。JVM进程也随即退出。

对于一个进程中的多个线程来说,多个线程共享进程的内存块,当有新的线程产生的时候,操作系统不分配新的内存,而是让新线程共享原有的进程块的内存。因此,线程间的通信很容易,速度也很快。不同的进程因为处于不同的内存块,因此进程之间的通信相对困难。

实际上,操作的系统的多进程实现了多任务并发执行,程序的多线程实现了进程的并发执行。多任务、多进程、多线程的前提都是要求操作系统提供多任务、多进程、多线程的支持。

在Java程序中,JVM负责线程的调度。线程调度是值按照特定的机制为多个线程分配CPU的使用权。调度的模式有两种:分时调度和抢占式调度。分时调度是所有线程轮流获得CPU使用权,并平均分配每个线程占用CPU的时间;抢占式调度是根据线程的优先级别来获取CPU的使用权。JVM的线程调度模式采用了抢占式模式。

所谓的“并发执行”、“同时”其实都不是真正意义上的“同时”。众所周知,CPU都有个时钟频率,表示每秒中能执行cpu指令的次数。在每个时钟周期内,CPU实际上只能去执行一条(也有可能多条)指令。操作系统将进程线程进行管理,轮流(没有固定的顺序)分配每个进程很短的一段是时间(不一定是均分),然后在每个线程内部,程序代码自己处理该进程内部线程的时间分配,多个线程之间相互的切换去执行,这个切换时间也是非常短的。因此多任务、多进程、多线程都是操作系统给人的一种宏观感受,从微观角度看,程序的运行是异步执行的。

用一句话做总结:虽然操作系统是多线程的,但CPU每一时刻只能做一件事,和人的大脑是一样的,呵呵。

二、Java与多线程

Java语言的多线程需要操作系统的支持。

Java 虚拟机允许应用程序并发地运行多个执行线程。Java语言提供了多线程编程的扩展点,并给出了功能强大的线程控制API。

在Java中,多线程的实现有两种方式: 扩展java.lang.Thread类 实现java.lang.Runnable接口

每个线程都有一个优先级,高优先级线程的执行优先于低优先级线程。每个线程都可以或不可以标记为一个守护程序。当某个线程中运行的代码创建一个新 Thread 对象时,该新线程的初始优先级被设定为创建线程的优先级,并且当且仅当创建线程是守护线程时,新线程才是守护程序。

当 Java 虚拟机启动时,通常都会有单个非守护线程(它通常会调用某个指定类的 main 方法)。Java 虚拟机会继续执行线程,直到下列任一情况出现时为止:

调用了 Runtime 类的 exit 方法,并且安全管理器允许退出操作发生。

非守护线程的所有线程都已停止运行,无论是通过从对 run 方法的调用中返回,还是通过抛出一个传播到 run 方法之外的异常。

三、扩展java.lang.Thread类

/** * File Name: TestMitiThread.java * Created by: IntelliJ IDEA.* Copyright: Copyright(c)2003-2006 * Company: Lavasoft([url]http://lavasoft.blog.51cto.com/[/url])* Author: leizhimin * Modifier: leizhimin * Date Time: 2007-5-17 10:03:12 * Readme: 通过扩展Thread类实现多线程 */ public class TestMitiThread { public static void main(String[] rags){ System.out.println(Thread.currentThread().getName()+ “ 线程运行开始!”);new MitiSay(“A”).start();new MitiSay(“B”).start();System.out.println(Thread.currentThread().getName()+ “ 线程运行结束!”);} }

class MitiSay extends Thread { public MitiSay(String threadName){ super(threadName);}

public void run(){ System.out.println(getName()+ “ 线程运行开始!”);for(int i = 0;i < 10;i++){ System.out.println(i + “ ” + getName());try { sleep((int)Math.random()* 10);} catch(InterruptedException e){ e.printStackTrace();} } System.out.println(getName()+ “ 线程运行结束!”);} }

运行结果:

main 线程运行开始!main 线程运行结束!A 线程运行开始!0 A 1 A B 线程运行开始!2 A 0 B 3 A 4 A 1 B 5 A 6 A 7 A 8 A 9 A A 线程运行结束!2 B 3 B 4 B 5 B 6 B 7 B 8 B 9 B B 线程运行结束!说明:

程序启动运行main时候,java虚拟机启动一个进程,主线程main在main()调用时候被创建。随着调用MitiSay的两个对象的start方法,另外两个线程也启动了,这样,整个应用就在多线程下运行。

在一个方法中调用Thread.currentThread().getName()方法,可以获取当前线程的名字。在mian方法中调用该方法,获取的是主线程的名字。

注意:start()方法的调用后并不是立即执行多线程代码,而是使得该线程变为可运行态(Runnable),什么时候运行是由操作系统决定的。

从程序运行的结果可以发现,多线程程序是乱序执行。因此,只有乱序执行的代码才有必要设计为多线程。

Thread.sleep()方法调用目的是不让当前线程独自霸占该进程所获取的CPU资源,以留出一定时间给其他线程执行的机会。

实际上所有的多线程代码执行顺序都是不确定的,每次执行的结果都是随机的。

四、实现java.lang.Runnable接口

/** * 通过实现 Runnable 接口实现多线程 */ public class TestMitiThread1 implements Runnable {

public static void main(String[] args){ System.out.println(Thread.currentThread().getName()+ “ 线程运行开始!”);TestMitiThread1 test = new TestMitiThread1();Thread thread1 = new Thread(test);Thread thread2 = new Thread(test);thread1.start();thread2.start();System.out.println(Thread.currentThread().getName()+ “ 线程运行结束!”);}

public void run(){ System.out.println(Thread.currentThread().getName()+ “ 线程运行开始!”);for(int i = 0;i < 10;i++){ System.out.println(i + “ ” + Thread.currentThread().getName());try { Thread.sleep((int)Math.random()* 10);} catch(InterruptedException e){ e.printStackTrace();} } System.out.println(Thread.currentThread().getName()+ “ 线程运行结束!”);} }

运行结果:

main 线程运行开始!Thread-0 线程运行开始!main 线程运行结束!0 Thread-0 Thread-1 线程运行开始!0 Thread-1 1 Thread-1 1 Thread-0 2 Thread-0 2 Thread-1 3 Thread-0 3 Thread-1 4 Thread-0 4 Thread-1 5 Thread-0 6 Thread-0 5 Thread-1 7 Thread-0 8 Thread-0 6 Thread-1 9 Thread-0 7 Thread-1 Thread-0 线程运行结束!8 Thread-1 9 Thread-1 Thread-1 线程运行结束!说明:

TestMitiThread1类通过实现Runnable接口,使得该类有了多线程类的特征。run()方法是多线程程序的一个约定。所有的多线程代码都在run方法里面。Thread类实际上也是实现了Runnable接口的类。

在启动的多线程的时候,需要先通过Thread类的构造方法Thread(Runnable target)构造出对象,然后调用Thread对象的start()方法来运行多线程代码。

实际上所有的多线程代码都是通过运行Thread的start()方法来运行的。因此,不管是扩展Thread类还是实现Runnable接口来实现多线程,最终还是通过Thread的对象的API来控制线程的,熟悉Thread类的API是进行多线程编程的基础。

五、读解Thread类API

static int MAX_PRIORITY 线程可以具有的最高优先级。static int MIN_PRIORITY 线程可以具有的最低优先级。static int NORM_PRIORITY 分配给线程的默认优先级。

构造方法摘要

Thread(Runnable target)分配新的 Thread 对象。Thread(String name)分配新的 Thread 对象。

方法摘要

static Thread currentThread()返回对当前正在执行的线程对象的引用。ClassLoader getContextClassLoader()返回该线程的上下文 ClassLoader。long getId()返回该线程的标识符。String getName()返回该线程的名称。int getPriority()返回线程的优先级。Thread.State getState()返回该线程的状态。ThreadGroup getThreadGroup()返回该线程所属的线程组。static boolean holdsLock(Object obj)当且仅当当前线程在指定的对象上保持监视器锁时,才返回 true。void interrupt()中断线程。

static boolean interrupted()测试当前线程是否已经中断。boolean isAlive()测试线程是否处于活动状态。boolean isDaemon()测试该线程是否为守护线程。boolean isInterrupted()测试线程是否已经中断。void join()等待该线程终止。void join(long millis)等待该线程终止的时间最长为 millis 毫秒。void join(long millis, int nanos)等待该线程终止的时间最长为 millis 毫秒 + nanos 纳秒。void resume()已过时。该方法只与 suspend()一起使用,但 suspend()已经遭到反对,因为它具有死锁倾向。有关更多信息,请参阅为何 Thread.stop、Thread.suspend 和 Thread.resume 遭到反对?。void run()如果该线程是使用独立的 Runnable 运行对象构造的,则调用该 Runnable 对象的 run 方法;否则,该方法不执行任何操作并返回。void setContextClassLoader(ClassLoader cl)设置该线程的上下文 ClassLoader。void setDaemon(boolean on)将该线程标记为守护线程或用户线程。

static void setDefaultUncaughtExceptionHandler(Thread.UncaughtExceptionHandler eh)设置当线程由于未捕获到异常而突然终止,并且没有为该线程定义其他处理程序时所调用的默认处理程序。void setName(String name)改变线程名称,使之与参数 name 相同。void setPriority(int newPriority)更改线程的优先级。

void setUncaughtExceptionHandler(Thread.UncaughtExceptionHandler eh)设置该线程由于未捕获到异常而突然终止时调用的处理程序。static void sleep(long millis)在指定的毫秒数内让当前正在执行的线程休眠(暂停执行)。static void sleep(long millis, int nanos)在指定的毫秒数加指定的纳秒数内让当前正在执行的线程休眠(暂停执行)。void start()使该线程开始执行;Java 虚拟机调用该线程的 run 方法。void stop()已过时。该方法具有固有的不安全性。用 Thread.stop 来终止线程将释放它已经锁定的所有监视器(作为沿堆栈向上传播的未检查 ThreadDeath 异常的一个自然后果)。如果以前受这些监视器保护的任何对象都处于一种不一致的状态,则损坏的对象将对其他线程可见,这有可能导致任意的行为。stop 的许多使用都应由只修改某些变量以指示目标线程应该停止运行的代码来取代。目标线程应定期检查该变量,并且如果该变量指示它要停止运行,则从其运行方法依次返回。如果目标线程等待很长时间(例如基于一个条件变量),则应使用 interrupt 方法来中断该等待。有关更多信息,请参阅《为何不赞成使用 Thread.stop、Thread.suspend 和 Thread.resume?》。void stop(Throwable obj)已过时。该方法具有固有的不安全性。请参阅 stop()以获得详细信息。该方法的附加危险是它可用于生成目标线程未准备处理的异常(包括若没有该方法该线程不太可能抛出的已检查的异常)。有关更多信息,请参阅为何 Thread.stop、Thread.suspend 和 Thread.resume 遭到反对?。void suspend()已过时。该方法已经遭到反对,因为它具有固有的死锁倾向。如果目标线程挂起时在保护关键系统资源的监视器上保持有锁,则在目标线程重新开始以前任何线程都不能访问该资源。如果重新开始目标线程的线程想在调用 resume 之前锁定该监视器,则会发生死锁。这类死锁通常会证明自己是“冻结”的进程。有关更多信息,请参阅为何 Thread.stop、Thread.suspend 和 Thread.resume 遭到反对?。String toString()返回该线程的字符串表示形式,包括线程名称、优先级和线程组。static void yield()暂停当前正在执行的线程对象,并执行其他线程。

六、线程的状态转换图

线程在一定条件下,状态会发生变化。线程变化的状态转换图如下:

1、新建状态(New):新创建了一个线程对象。

2、就绪状态(Runnable):线程对象创建后,其他线程调用了该对象的start()方法。该状态的线程位于可运行线程池中,变得可运行,等待获取CPU的使用权。

3、运行状态(Running):就绪状态的线程获取了CPU,执行程序代码。

4、阻塞状态(Blocked):阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。阻塞的情况分三种:

(一)、等待阻塞:运行的线程执行wait()方法,JVM会把该线程放入等待池中。

(二)、同步阻塞:运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入锁池中。

(三)、其他阻塞:运行的线程执行sleep()或join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。

5、死亡状态(Dead):线程执行完了或者因异常退出了run()方法,该线程结束生命周期。

七、线程的调度

1、调整线程优先级:Java线程有优先级,优先级高的线程会获得较多的运行机会。

Java线程的优先级用整数表示,取值范围是1~10,Thread类有以下三个静态常量: static int MAX_PRIORITY 线程可以具有的最高优先级,取值为10。static int MIN_PRIORITY 线程可以具有的最低优先级,取值为1。static int NORM_PRIORITY 分配给线程的默认优先级,取值为5。

Thread类的setPriority()和getPriority()方法分别用来设置和获取线程的优先级。

每个线程都有默认的优先级。主线程的默认优先级为Thread.NORM_PRIORITY。

线程的优先级有继承关系,比如A线程中创建了B线程,那么B将和A具有相同的优先级。JVM提供了10个线程优先级,但与常见的操作系统都不能很好的映射。如果希望程序能移植到各个操作系统中,应该仅仅使用Thread类有以下三个静态常量作为优先级,这样能保证同样的优先级采用了同样的调度方式。

2、线程睡眠:Thread.sleep(long millis)方法,使线程转到阻塞状态。millis参数设定睡眠的时间,以毫秒为单位。当睡眠结束后,就转为就绪(Runnable)状态。sleep()平台移植性好。

3、线程等待:Object类中的wait()方法,导致当前的线程等待,直到其他线程调用此对象的 notify()方法或 notifyAll()唤醒方法。这个两个唤醒方法也是Object类中的方法,行为等价于调用 wait(0)一样。

4、线程让步:Thread.yield()方法,暂停当前正在执行的线程对象,把执行机会让给相同或者更高优先级的线程。

5、线程加入:join()方法,等待其他线程终止。在当前线程中调用另一个线程的join()方法,则当前线程转入阻塞状态,直到另一个进程运行结束,当前线程再由阻塞转为就绪状态。

6、线程唤醒:Object类中的notify()方法,唤醒在此对象监视器上等待的单个线程。如果所有线程都在此对象上等待,则会选择唤醒其中一个线程。选择是任意性的,并在对实现做出决定时发生。线程通过调用其中一个 wait 方法,在对象的监视器上等待。直到当前的线程放弃此对象上的锁定,才能继续执行被唤醒的线程。被唤醒的线程将以常规方式与在该对象上主动同步的其他所有线程进行竞争;例如,唤醒的线程在作为锁定此对象的下一个线程方面没有可靠的特权或劣势。类似的方法还有一个notifyAll(),唤醒在此对象监视器上等待的所有线程。注意:Thread中suspend()和resume()两个方法在JDK1.5中已经废除,不再介绍。因为有死锁倾向。

7、常见线程名词解释

主线程:JVM调用程序mian()所产生的线程。

当前线程:这个是容易混淆的概念。一般指通过Thread.currentThread()来获取的进程。后台线程:指为其他线程提供服务的线程,也称为守护线程。JVM的垃圾回收线程就是一个后台线程。

前台线程:是指接受后台线程服务的线程,其实前台后台线程是联系在一起,就像傀儡和幕后操纵者一样的关系。傀儡是前台线程、幕后操纵者是后台线程。由前台线程创建的线程默认也是前台线程。可以通过isDaemon()和setDaemon()方法来判断和设置一个线程是否为后台线程。

智能车编程总结 篇9

分类: C语言学习心得体会 2010-08-08 19:33 63人阅读 评论(1)收藏 举报

转载请注明出处:http://blog.csdn.net/ecorefeng

在编程过程中会遇到各种各样的错误与警告,这里我对编程过程中经常遇到的细节或者说常出错的地方进行了简单的总结,希望对正在编程的“童鞋”有所帮助:

C语言编程提示的总结:

1:使用 #include 指令避免重复声明

2:使用 #define 指令给常量值取名

3:在 #include 文件中放置函数原型

4:在使用下标前先检查它们的值

5:在 while 或 if 表达式中蕴含赋值操作

6:如何编写一个空循环体

7:始终要进行检查,确保数组不越界

8:良好的程序风格和文档将使程序容易阅读和维护

9:为了保持最佳的可移植性,把字符的值限制在有符号和无符号字符范围的交集之内,或者不要在字符上执行算术运算

10:用它们在使用时最自然的形式来表示字面值

11:不要把整型值和枚举值混在一起使用

12:不要依赖隐式声明

13:在定义类型的新名字时,使用 typedef 而不是 #define

14:用 const 声明其值不会修改的变量

15:使用名字常量而不是字面值常量

16:不要在嵌套的代码块之间使用相同的变量名

17:在一个没有循环体的循环中,用一个分号表示空语句,并让它独占一行

18: for 循环的可读行比 while 循环强,因为它把用于控制循环的表达式收集起来放在一个地方

19:在每个 switch 语句中都使用 default 子句

20:使用符号赋值符可以使用程序更容易维护

21:使用条件操作符代替 if 语句以简化表达式

22:使用逗号操作符来消除多余的代码

23:不要混用整型和布尔型值

24:一个值应该只具一种意思

25:如果指针并不指向任何有意义的东西,使它非法地指向了数组第 1 个元素的前面的内存位置

26:在函数原型中使用参数名,可以给使用该函数的用户提供更多的信息

27:抽象数据类型可以减少程序对模块实现细节的依赖,从而提高程序的可靠性

28:当递归定义清晰地优点可以补偿它的效率开销时,就可以使用这个工具

29:一开始就编写良好的代码显然比依赖编译器来修正劣质代码更好

30:源代码的可读性机会总是比程序的运行时效率更为重要

31:只要有可能,函数的指针参都应该声明为 const

32:在有些环境中,使用 register 关键字提高程序的运行时效率

33:在多维数组的初始值列表中使用完整的多层花括号能提高可读性

34:不要试图自己编写功能相同的函数来取代库函数

35:使用字符分类和转换函数可以提高函数的移植性

36:把结构标签声明和结构的 typedef 声明放在头文件中,当源文件需要这些声明时可以通过 #include 指令把它们包含进来

37::结构成员的最佳排列形式并不一定就是考虑边界对齐而浪费空间最少的那种排列形式

38:把位段成员显示地声明为 signed in 或 unsigned 类型

39:位段是不可移植的40:位段时源代码中位的操作表达得更为清楚

41:动态内存分配有助于消除程序内部存在的限制

42:使用 sizeof 计算数据类型的长度,提高程序的可移植性

43:消除特殊情况使代码更容易维护

44:通过锻炼语句消除 if 语句中的重复语句

45:不要仅仅根据代码的大小评估它的质量

46:如果并非必要,避免使用多层间接访问

47: cdecl 程序可以帮助你分析复杂的声明

48:把 void* 强制转换为其他类型的指针时必须小心

49:使用转移表时,应始终验证下标的有效性

50:破坏性的命令行参数处理方式使你以后无法再进行处理

51:不寻常的代码始终应该加上一条注释,描述它的目的和原理

52:避免用 #define 指令定义可以用函数实现的很长序列的代码

53:在那些对表达式求值的宏中,每个宏参数出现的地方都应该加上括号,并且在整个宏定义的两边也加上括号

54:避免使用 #define 宏创建一种新语言

55:采用命名约定,使程序员很容易看出某个标识符是否为 #define 宏

56:只要合适就应该使用文件包含,不比担心它的额外开销

57:头文件只应该包含一组函数和(或)数据的声明

58:把不同集合的声明分离到不同的头文件中可以改善信息隐藏

59:嵌套的 #include 文件使我们很难判断源文件之间的依赖关系

60:在可能出现错误的场合,检查并报告错误

61:操纵文本行而无需顾及它们的外部标识形式,这个能力有助于提高程序的可移植性

62:使用 scanf 限定提高可移植性

63:当你打印长整数时,即使你所使用的机器并不需要,坚持使用 1 修改符可以提高可移植性

64:滥用 setjmp 和 longjmp 可能导致晦涩难懂的代码

65:对信号进行处理将导致程序的可移植性变差

66:使用断言可以简化程序的调试

67:避免使用具有副作用的函数可以使程序更容易理解

68:一个模块的接口应该避免暴漏它的细节

69:将数据类型参数化,是它更容易修改

70:只有模块对外公布的接口才应该是公用的71:使用断言来防止非法操作

72:几个不同的实现使用同一个通用接口是模块具有更强的可互换性

73:复用现存的代码而不是对它进行改写

74:迭代比尾部递归效率更高

75使用 stdarg 实现可变参数列表

76:改进算法比优化代码更有效率

77:使用某种环境特有的技巧会导致程序不可移植

上一篇:架子工劳务承包合同下一篇:少先队半年工作总结