天马阁

 找回密码
 立即注册
                                        →→→→→→→→→→→→ 1点击查看所有VIP教程目录长列表(总教程数269个) 2办理VIP详情进入 ←←←←←←←←←←←←
1 x64CE与x64dbg入门基础教程 7课 已完结 2 x64汇编语言基础教程 16课 已完结 3 x64辅助入门基础教程 9课 已完结 4 C++x64内存辅助实战技术教程 149课 已完结
5 C++x64内存检测与过检测技术教程 10课 已完结 6 C+x64二叉树分析遍历与LUA自动登陆教程 19课已完结 7 C++BT功能原理与x64实战教程 29课 已完结 8 C+FPS框透视与自瞄x64实现原理及防护思路 30课完结
64驱?封? 9 64反驱? 10 64位V? 11 绝? 12 ???课?
13 64透 ? 14 64U ? 15 64Q ? 16 64功 ?
17 64U ? 18 64模 ? 19 64多 ? 20 64网 ?
21 64注 ? 22 64火 ? 23 64棋 ? 24 64自二链L?
25 64破 ? VIP会员办理QQ: 89986068   
【请先加好友,然后到好友列表双击联系客服办理,不然可能无法接受到信息。】
27 加入2000人交流群637034024 3 28 免责声明?
查看: 4512|回复: 0

浅谈多线程、许可区编程.

[复制链接]

14

主题

0

回帖

17

积分

编程入门

Rank: 1

天马币
28
发表于 2024-2-29 12:45:17 | 显示全部楼层 |阅读模式
谈谈我自己对多线程上的理解,因本人知识有限,如有不对之处请各位高手多多指正、补充,同时,在多线程上有问题而不能解决的易友,可以将自己问题提出,并附上源码(不愿提供源码别找我,我不是神,无法猜测出问题所在),我将会一一测试,并在本人能力范围内解决:

一、简介
1、线程句柄与线程:
①、关闭线程句柄对线程的运行不会有影响,关闭句柄并不代表结束线程;
②、线程句柄是用于对线程挂起、恢复、结束等操作,线程创建后,都会有一个线程句柄,如果不需要对线程句柄进行操作,建议立即关闭线程句柄;
③、线程句柄必须在适当的时候关闭,否则会造成句柄泄露,但不同于内存泄露。

2、死锁、循环死锁、活锁
①、死锁:线程A占有资源A,线程B占有资源B,线程A申请占有资源B,同时要求占有资源B之后才释放资源A,而线程B申请占有资源A,同时要求占有资源A之后才释放资源B,这样两个线程互相永久等待对方释放资源,这就是死锁。
②、循环死锁:线程A占有资源A,线程B占有资源B,线程C占有资源C,线程A申请占有资源B,同时要求占有资源B之后才释放资源A,而线程B申请占有资源C,同时要求占有资源C之后才释放资源B,线程C申请占有资源A,同时要求占有资源A之后才释放资源C,这样线程互相永久等待对方释放资源,这就是循环死锁。
③、活锁:提交任务之后,任务永远处于等处理状态,这就是活锁。这种情况比较少见,但是出现这种情况,将比死锁更加不易查觉,避免活锁的简单方法是采用先来先处理。

二、注意事项
1、虽然启动线程要比启动进程要快,但是启动线程仍是比较耗时的,因此,不要频繁的启动、退出线程,而是启动线程后将各种任务处理完成后才退出(这种和线程池差不多);
2、对窗口各种组件操作,最好是在创建该窗口的线程上进行操作,如果在其它线程上操作,可能会引起程序出错等情况(该错误是随机出现的)。(未找到直接又安全的调用其他线程创建的组件的方法,有知道的人,麻烦告诉一下,谢谢!)
3、线程运行次序并不是按照我们创建他们时的顺序来运行的,CPU处理线程的顺序也是不确定的。
4、读/写共享资源时一般需要使用许可区,当然,在明知读/写共享资源不会出现错误时,就不需要许可区,这样可提高性能。
5、在编写多线程时,必须以多线程的方式考虑读/写共享资源,以避免出错,不然的话,可能会出现各种问题,如:意外退出、在单核CPU上可以稳定运行的多线程程序一到多核CPU上运行就出错。
6、线程中如果需要使用COM对象时,要需将COM对象初始化。
7、结束线程时,应该使用正常的控制代码使线程退出,强烈反对使用强制结束线程(),该命令极可能造成一些资源未释放,从而导致程序的不稳定。
8、线程不能频繁的发消息给窗口,频繁的发消息给窗口,可能会造成窗口响应其他事件的缓慢,也是就让人感觉程序运行很慢;
9、要注意避免各种死锁、活锁发生,确实无法避免的话,就只能想法解锁,同时得注意解锁时引发的新的问题。

三、多线程的误区
1、使用处理事件()。非窗口的线程是没有窗口消息循环,而处理事件()命令是用于消息循环,因此在非窗口的线程上是不必加入“处理事件()”命令;
2、线程越多越好。线程并非越多越好,有些人将单线程改成多线程后,发现程序能处理更多的任务了,实际上这种方法是建立别的程序的痛苦之上(当然系统有空闲资源就并当别论了),别的程序可能因此而变慢。并且,线程数过多,会使CPU在线程间切换的开销增加,因而使速度变慢,降低系统性能。在一些阻塞式、耗资源少的线程上需要适当的增加线程数量,以免程序无响应。

四、许可区
1、许可区(一般称为临界区),不论是硬件许可资源,还是软件许可资源,多个线程必须互斥地对它进行访问,每个线程中访问许可资源的那段代码称为许可区。
2、注意事项:
①、如果有若干线程要求进入许可区,一次仅允许一个线程进入;
②、任何时候,处于许可区内的线程不可多于一个。如已有线程进入自己的许可区,则其它所有试图进入许可区的线程将被挂起,并一直持续到进入许可区的线程退出;
③、进入一个空闲的许可区时,耗时极少,但是进入一个需等待的许可区时,耗时相对较长,因此需要避免经常出现进入需等待的许可区;
④、创建后许可区,在不再使用时,需要将其删除;
⑤、在使用许可区时,应尽量减少许可区内代码,避免使用需长时间处理的代码,使进入许可区的线程能尽快退出,以便其它线程能进入许可区;
⑥、避免将整个线程处于许可区内,尽管它不会出错,但是由于后来要求进入许可区的线程全部会被挂起,也就会出现虽然是多线程,但实际是以单线程方式执行;
⑦、访问相同的许可资源时,必须是以相同的许可区进入访问,以不同的许可区进入访问将可能会使许可区变的无意义(我在这个坑里蹲了很久,郁闷啊!)。
3、许可区缺点
①、无法侦测某个许可区是否可进入。

五、线程同步

1、临界区(CriticalSection)
易语言中称为许可区,这种速度最快,但只能用于本进程的线程同步;

2、事件(Event)
事件可以跨进程使用,它有两种状态、两种类型:有信号状态和无信号状态、手动重置事件和自动重置事件。手动重置事件被设置为有信号状态后,会唤醒所有等待的线程,而且一直保持为有信号状态,直到程序重新把它设置为无信号状态。自动重置事件被设置为有信号状态后,会唤醒“一个”等待中的线程,然后自动恢复为无信号状态。

3、互斥器(Mutex)
互斥器的功能和临界区很相似,互斥器所花费的时间比临界区多的多,同时它可以跨进程使用。等待一个被锁住的互斥器可以设定超时退出,不会像临界区那样无法得知临界区的情况,而一直死等。

4、信号量(Semaphore)
与临界区相比,它信号量可以跨进程使用,可以设定同时进入资源总数。

六、线程通信
线程通信是一般都是需要配合线程同步来使用:
1、使用全局变量进行通信,推荐使用这种方法,该是最快、最方便的通信方式;
2、使用消息通信(需要有消息队列才能使用);
3、使用Socket进行通信(可以跨计算机使用);

附:更正一下:对象.发送信息()、对象.投递信息()多线程中也不是稳定的,应该使用SendMessage()、PostMessage()。感谢hesiyuanmm的反馈。

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

天马阁|C/C++辅助教程|安卓逆向安全| 论坛导航|免责申明|Archiver||网站地图
拒绝任何人以任何形式在本论坛发表与中华人民共和国法律相抵触的言论,本站内容均为会员发表,并不代表天马阁立场!
任何人不得以任何方式翻录、盗版或出售本站视频,一经发现我们将追究其相关责任!
我们一直在努力成为最好的编程论坛!
Copyright© 2010-2021 All Right Reserved.
快速回复 返回顶部 返回列表