易语言多线程Api封装线程挂起恢复销毁

141 篇文章 5 订阅
168 篇文章 11 订阅

封装多线程模块-api-线程的挂起和恢复销毁

强制杀死或挂起线程会导致线程正在获取的锁资源无法释放;如果正在操作一块公共内存,可能会导致公共内存被破坏。
一、SuspendThread
在实际环境中,调用SuspendThread时必须小心,因为不知道暂停线程运行时它在进行什么操作。如果线程试图从堆栈中分配内存,那么该线程将在该堆栈上设置一个锁。当其他线程试图访问该堆栈时,这些线程的访问就被停止,知道第一个线程恢复运行 。只有确切知道目标线程是什么(或者目标线程正在做什么),并且采取强有力的措施来避免因暂停线程的运行而带来的问题或死锁状态,suspendThread才是安全的。

511遇见易语言多线程大漠多线程


二、ResumeThread
使线程的挂起时间计数减一。创建一个挂起的线程或者手动挂起一个线程后调用。调用该函数后线程不一定会立刻执行,而是由操作系统继续调度,直到计数为0,系统为其分配资源时才开始执行。
ResumeThread函数并不能保证线程真地继续执行,为什么呢?每一个线程都有一个线程暂停计数器,当线程正在运行时计数器为0,当其他线程对此线程使用SuspendThread函数时计数器会增加1,调用ResumeThread会使计数器减小1,所以当调用SuspendThread函数后计数器变为1。但是Windows是一个多线程操作系统,所以很有可能某个其他的线程也对此线程调用了SuspendThread,这时计数器就会变为2,这时再调用ResumeThread只会使计数器变回为1,线程将继续暂停,直到计数器变为0。那么,如何确定线程是否真地被继续执行了呢?很简单,检查函数返回值就可以了。如果返回值为0,则表示线程已经恢复执行了,如果不为0,则表示线程继续被暂停,如果为0xffffffff,则说明函数调用失败了。
三、忠告建议:
1、如果线程正在进行堆分配时被强行撤销,可能会破坏堆,造成堆锁没有释放,如果这时其他线程进行堆分配就会陷入死锁。
2、来之MSDN的血淋淋的警告:
a. If the target thread owns a critical section, the critical section will not be released.(如果目标线程持有着一个临界区(critical section),这临界区将不会被释放。)
b. If the target thread is allocating memory from the heap, the heap lock will not be released. (如果目标线程正在堆里分配内存,堆锁(heap lock)将不会被释放。)
c. If the target thread is executing certain kernel32 calls when it is terminated, the kernel32 state for the thread's process could be inconsistent. (如果目标线程在结束时调用了某些kernel32,会造成kernel32的状态不一致。)
d. If the target thread is manipulating the global state of a shared DLL, the state of the DLL could be destroyed, affecting other users of the DLL. (如果目标线程正在更改一个共享DLL的全局状态,这个共享DLL的状态可能会被破坏,影响到其他的正在使用这个DLL库的线程。
四、大漠建议:
' 然后我们说一下系统的多线程
' 系统的多线程其实就是创建,暂停,恢复,强制结束这4个接口
' 先告诉大家结论,暂停这个接口,永远不要去调用. 强制结束这个接口要尽可能避免调用.
' 很多用户为了方便,在暂停某个脚本时,使用了系统提供的暂停接口
' 结果导致了各种卡死,崩溃。 还不知道咋回事。 感觉明明代码写的没毛病啊
' 这里我要说一下,系统提供的暂停(SuspendThread)操作,压根就不是给正常用户使用的,这是给调试器使用的
' 那为何这个暂停操作会导致异常呢? 实际上,线程在运行当中,它的状态是不可控的
' 假如你要暂停的线程正好处于某个锁当中(E语言也叫做许可证),万一恰巧这个锁还是个全局的,你说会发生什么事情?
' 而恰巧的是,系统中使用全局锁的操作很频繁. 比如分配内存/释放内存.
' 所以我给大家的建议是,永远不要去用暂停这个接口.
' 至于强制结束线程,也是非常不建议使用,它和暂停线程有相同的作用. 假如结束的线程正好处于锁当中,BOOM!!!
' 那么今天的例子也就是给大家演示,如何不用这几个要命的接口,如何正确的使用多线程.
' 至于上面说的暂停,恢复我们有别的方法替代完成.
五、最后总结
1、不要调用 SuspendThread 暂停线程,不要用 TerminateThread 结束线程, 造成死锁的情况。
2、win32下的API基本都是线程安全的,因此API里面有很多线程同步的地方,LoadLibrary里面有一个临界区,线程函数在执行到LoadLibrary里面之后,如果刚好走到LoadLibrary的临界区里面,此时主线程的ontimer触发,将该线程挂起,ontimer继续执行,运行到LoadLibrary后,由于线程中LoadLibrary还没有从临界区出来,此时就造成主线程ontimer里面的LoadLibrary无限等待,主线程挂起。
3、因此不建议用suspend暂停线程,MSDN也有说明,suspend最好只在debug里面使用。
4、那怎么使线程挂起呢?监视线程的状态。

参考:511遇见易语言多线程大漠多线程-15Api封装线程挂起恢复销毁

  • 0
    点赞
  • 0
    收藏
  • 打赏
    打赏
  • 0
    评论
解决:软件多线程运行时遇到【内存不断升高】甚至爆表! 因为本人是个小白,多线程经常用,但是线程池并没有用过,(一听到线程池,总感觉高大上) 但是近期写彩票软件的时候发现,多线程长期操作会导致内容不断的升高直至报错,遂想线程池,完善后发现不是一般的叼 啊!!! 先简单的说下多线程线程池的区别: 1、多线程每次启动的时候系统都要分配一定的资源出来(主要占的就是内存),而不断的启动线程、启动线程、启动线程 循环的启动线程,就造成了系统资源极大的浪费,甚至不释放的情况,继续下去内存就OVER了! 2、线程池则完美的解决了这个问题,线程池的原理就是事先申请好指定数量的线程所使用的资源,而且这些资源是不断的重复利用的!可利用任务管理器看到程序的线程数量的变化(在使用普通的多线程时:线程数会根据软件启动的线程数量增加,循环完了之后线程数量也就减少了,但是内存资源不减少,再启动线程内存继续飙升!  而在使用【线程池】的时候:线程数一直保持线程池中的数量,无论你是否启动多线程进行运算,线程数量都不会变化,同时内存也不会有多大的变化,更不会不断的飙升!) 也许我的表达能力不足,反正大家知道在启用多线程的时候尽量使用线程池可以保证内存不会飙升就行了! 这里说的启动多线程是指循环启动‘同一个子程序’线程
前文: 为了能充分理解本篇文章的内容,需要了解的知识如下: 1.事件对象的使用:http://baike.baidu.com/view/751499.htm 2.信号量的使用:http://baike.baidu.com/view/1285861.htm 3.等待单一对象,等待多个对象的使用:http://baike.baidu.com/view/1424795.htm, http://baike.baidu.com/view/908866.htm 4.链表,队列——易语言数据结构支持库的使用:见易语言帮助文档 5.多线程间的许可证的使用:见易语言帮助文档 6.原子锁操作:http://baike.baidu.com/view/6235756.htm (链接仅供参考 ) 一.了解线程池的运行原理: 线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务。线程线程都是后台 线程。每个线程都使用默认的堆栈 大小,以默认的优先级运行,并处于多线程单元中。超过最大值的线程可以排队,但他们要等到其他线程完成后才启动。 具体参见:http://baike.baidu.com/view/262150.htm 二.实现的过程概述: 1.通过一个主线程来监视是否有新任务,如果有新任务,则判断当前的线程数是否大于最大线程数,如果小于最大线程数则创建新线程,反之则加入线程队列等待执行。 2.当时间经过过长(1 分钟,可手动设置)主线程会自动关闭一部分的线程,保留最小线程数,来释放资源。 3.执行任务的线程等待队列,如果队列中有任务,则执行任务,如果队列中没有任务,则进入内核等待状态,当队列中有任务时继续执行。而不是重复性创建和销毁线程。 具体请看上图。 三.线程句柄的管理 每次新建线程时,将自动将内部的_ID 增加 1 ,保存到“类 _ 线程句柄数组管理”中,该类以链表存储的方式,保存所有的线程句柄和 ID 。当销毁线程池或关闭子线程时时,关闭所有或对应的句柄。 四.任务队列的实现 任务队列采用易语言中的“数据结构支持库”中的“队列”,队列为:先进先出,这样保证是按照先后顺序来进行的,而且弹出后会自动在队列中删除,使用方便。在有新任务时,由主线程将任务信息压入队列,并且设置“内部_ 线程池数据 .__ 监视任务队列信号量”的计数值 +1 ,子线程通过监听这个事件,从队列中弹出获取一个信息,然后进行执行。 五.销毁的实现 当执行销毁线程池的命令时,设置“__ 线程池退出事件信号量”为有信号,使主线程退出循环并执行清理代码,设置“ __ 子线程结束信号量”计数值为最大(虽然不用这么大),保证每个线程都退出。而后主线程监视所有的子线程退出 ?,如果超过“超时时间”则强制销毁所有子线程,并且释放其他资源,返回。 ?监视方法:主线程监视:“子线程退出完毕事件”事件,子线程每次退出都会递减:“内部_ 线程池数据 .__ 运行子线程数”的值,如果“内部 _ 线程池数据 .__ 运行子线程数” =0 ,则会设置“子线程退出完毕事件”为有信号,表示所有子线程都退出了,然后执行清理工作。 难免会存在疏漏,请批评指正。 回复可以直接下载源码进行学习哦~

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:酷酷鲨 设计师:CSDN官方博客 返回首页
评论

打赏作者

511遇见

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值