西西软件下载最安全的下载网站、值得信赖的软件下载站!
缁崵绮哄銉ュ徔
U婢堆冪瑎v4.7.37.56 閺堚偓閺傛壆澧�U婢堆冪瑎v4.7.37.56 閺堚偓閺傛壆澧�
HD Tune  Prov5.75 濮瑰瀵茬紒鑳閻楃懓鍩嗛悧锟�HD Tune Prov5.75 濮瑰瀵茬紒鑳閻楃懓鍩嗛悧锟�
DiskGenius 娑撴挷绗熼悧鍦�5.2.1.941 鐎规ɑ鏌熼悧锟�DiskGenius 娑撴挷绗熼悧鍦�5.2.1.941 鐎规ɑ鏌熼悧锟�
360鏉烆垯娆㈢粻鈥愁啀v7.5.0.1460 鐎规ɑ鏌熼張鈧弬鎵360鏉烆垯娆㈢粻鈥愁啀v7.5.0.1460 鐎规ɑ鏌熼張鈧弬鎵
Cpu-Z娑擃厽鏋冮悧鍧�1.98.0 缂佽儻澹婃稉顓熸瀮閻楋拷Cpu-Z娑擃厽鏋冮悧鍧�1.98.0 缂佽儻澹婃稉顓熸瀮閻楋拷
缂冩垹绮跺銉ュ徔
閼垫崘顔嗛悽浣冨壋缁犫€愁啀V15.2 鐎规ɑ鏌熷锝呯础閻楋拷閼垫崘顔嗛悽浣冨壋缁犫€愁啀V15.2 鐎规ɑ鏌熷锝呯础閻楋拷
office2016濠碘偓濞茶浼愰崗绌攎sv19.5.2 鐎规ɑ鏌熼張鈧弬鎵office2016濠碘偓濞茶浼愰崗绌攎sv19.5.2 鐎规ɑ鏌熼張鈧弬鎵
鏉╁懘娴�11閺堚偓閺傛壆澧梫11.3.6.1870 鐎规ɑ鏌熼悧锟�鏉╁懘娴�11閺堚偓閺傛壆澧梫11.3.6.1870 鐎规ɑ鏌熼悧锟�
360閸忓秷鍨倃ifi5.3.0.5000 鐎规ɑ鏌熼張鈧弬鎵360閸忓秷鍨倃ifi5.3.0.5000 鐎规ɑ鏌熼張鈧弬鎵
360鐎瑰鍙忓ù蹇氼潔閸o拷2022v13.1.5188.0 鐎规ɑ鏌熷锝呯础閻楋拷360鐎瑰鍙忓ù蹇氼潔閸o拷2022v13.1.5188.0 鐎规ɑ鏌熷锝呯础閻楋拷
婢舵艾鐛熸担鎾惰
闁伴攱鍨滈棅鍏呯閻╋拷2022v9.1.6.2 鐎规ɑ鏌熷锝呯础閻楋拷闁伴攱鍨滈棅鍏呯閻╋拷2022v9.1.6.2 鐎规ɑ鏌熷锝呯础閻楋拷
閺嗘挳顥撹ぐ閬嶇叾2021V5.81.0202.1111鐎规ɑ鏌熷锝呯础閻楋拷閺嗘挳顥撹ぐ閬嶇叾2021V5.81.0202.1111鐎规ɑ鏌熷锝呯础閻楋拷
韫囶偅鎸�5.0濮橀晲绗夐崡鍥╅獓閻楋拷5.0.80 妤犮劌銇旈悧锟�韫囶偅鎸�5.0濮橀晲绗夐崡鍥╅獓閻楋拷5.0.80 妤犮劌銇旈悧锟�
娴兼﹢鍙�2022鐎广垺鍩涚粩鐤�8.0.9.11050 鐎规ɑ鏌熼張鈧弬鎵娴兼﹢鍙�2022鐎广垺鍩涚粩鐤�8.0.9.11050 鐎规ɑ鏌熼張鈧弬鎵
閻栧崬顨岄懝楦款潒妫版叆13.1.5鐎规ɑ鏌熺€瑰宕滈悧锟�閻栧崬顨岄懝楦款潒妫版叆13.1.5鐎规ɑ鏌熺€瑰宕滈悧锟�
閸ユ儳鑸伴崶鎯у剼
photoshop cs6 娑擃厽鏋冮悧锟�13.1.2.3 閸忓秷鍨傛稉顓熸瀮閻楋拷photoshop cs6 娑擃厽鏋冮悧锟�13.1.2.3 閸忓秷鍨傛稉顓熸瀮閻楋拷
Autodesk 3ds Max 2012鐎规ɑ鏌熺粻鈧担鎾茶厬閺傚洨澧梉32&64]Autodesk 3ds Max 2012鐎规ɑ鏌熺粻鈧担鎾茶厬閺傚洨澧梉32&64]
CAD2007閸忓秷鍨傛稉顓熸瀮閻楋拷CAD2007閸忓秷鍨傛稉顓熸瀮閻楋拷
vc鏉╂劘顢戞惔锟�2019閺堚偓閺傛壆澧梫2019.3.2(32&64娴o拷)vc鏉╂劘顢戞惔锟�2019閺堚偓閺傛壆澧梫2019.3.2(32&64娴o拷)
.NET Framework 4.8鐎规ɑ鏌熼悧锟�4.8.3646.NET Framework 4.8鐎规ɑ鏌熼悧锟�4.8.3646
閼卞﹤銇夐懕鏃傜捕
QQ2022v9.5.6.28129 鐎规ɑ鏌熼張鈧弬鎵QQ2022v9.5.6.28129 鐎规ɑ鏌熼張鈧弬鎵
瀵邦喕淇婇悽浣冨壋閻楋拷2022v3.5.0.44 鐎规ɑ鏌熷锝呯础閻楋拷瀵邦喕淇婇悽浣冨壋閻楋拷2022v3.5.0.44 鐎规ɑ鏌熷锝呯础閻楋拷
閸楀啰澧伴崡鏍ь啀瀹搞儰缍旈獮鍐插酱v9.02.02N 鐎规ɑ鏌熼悧锟�閸楀啰澧伴崡鏍ь啀瀹搞儰缍旈獮鍐插酱v9.02.02N 鐎规ɑ鏌熼悧锟�
QT鐠囶參鐓禫4.6.80.18262鐎规ɑ鏌熼張鈧弬鎵QT鐠囶參鐓禫4.6.80.18262鐎规ɑ鏌熼張鈧弬鎵
妞嬬偘淇�2018V6.2.0700 鐎规ɑ鏌熷锝呯础閻楋拷妞嬬偘淇�2018V6.2.0700 鐎规ɑ鏌熷锝呯础閻楋拷
閻㈢喐妞块張宥呭
閺€顖欑帛鐎规繈鎸堕崠锟�(Alipay)V10.2.53.7000 鐎瑰宕滈悧锟�閺€顖欑帛鐎规繈鎸堕崠锟�(Alipay)V10.2.53.7000 鐎瑰宕滈悧锟�
閻ф儳瀹抽崷鏉挎禈鐎佃壈鍩�2022V15.12.10 鐎瑰宕滈幍瀣簚閻楋拷閻ф儳瀹抽崷鏉挎禈鐎佃壈鍩�2022V15.12.10 鐎瑰宕滈幍瀣簚閻楋拷
閹靛婧€濞fê鐤傜€广垺鍩涚粩鐥�10.8.40鐎规ɑ鏌熼張鈧弬鎵閹靛婧€濞fê鐤傜€广垺鍩涚粩鐥�10.8.40鐎规ɑ鏌熼張鈧弬鎵
閻e懘鈧梻缍夐幍瀣簚鐎广垺鍩涚粩鐥�5.6.9 鐎规ɑ鏌熼張鈧弬鎵閻e懘鈧梻缍夐幍瀣簚鐎广垺鍩涚粩鐥�5.6.9 鐎规ɑ鏌熼張鈧弬鎵
閸楀啳浜伴惌銉ㄧ槕閺堝秴濮焌ppv4.5.1鐎规ɑ鏌熼悧锟�閸楀啳浜伴惌銉ㄧ槕閺堝秴濮焌ppv4.5.1鐎规ɑ鏌熼悧锟�
瑜伴亶鐓堕幘顓熸杹
p2psearcher鐎瑰宕滈悧锟�7.3  閹靛婧€閻楋拷p2psearcher鐎瑰宕滈悧锟�7.3 閹靛婧€閻楋拷
闁伴瀚嶉棅鍏呯2022鐎规ɑ鏌熼悧鍦�11.0.8 鐎规ɑ鏌熺€瑰宕滈悧锟�闁伴瀚嶉棅鍏呯2022鐎规ɑ鏌熼悧鍦�11.0.8 鐎规ɑ鏌熺€瑰宕滈悧锟�
閻栧崬顨岄懝鐑樺閺堣櫣澧梫13.1.0閻栧崬顨岄懝鐑樺閺堣櫣澧梫13.1.0
閻ф儳瀹宠ぐ閬嶇叾7.13.0 鐎规ɑ鏌熼張鈧弬鎵閻ф儳瀹宠ぐ閬嶇叾7.13.0 鐎规ɑ鏌熼張鈧弬鎵
瑜伴亶鐓堕崗鍫ユ敱v6.9.0 鐎瑰宕滈幍瀣簚閻楋拷瑜伴亶鐓堕崗鍫ユ敱v6.9.0 鐎瑰宕滈幍瀣簚閻楋拷
闂冨懓顕板銉ュ徔
閼垫崘顔嗛崝銊︽瀬V9.11.5 鐎瑰宕滈悧锟�閼垫崘顔嗛崝銊︽瀬V9.11.5 鐎瑰宕滈悧锟�
娑旓附妫楃亸蹇氼嚛閸忓秷鍨傞悧鍫熸拱v11.5.5.153 鐎规ɑ鏌熼張鈧弬鎵娑旓附妫楃亸蹇氼嚛閸忓秷鍨傞悧鍫熸拱v11.5.5.153 鐎规ɑ鏌熼張鈧弬鎵
QQ闂冨懓顕伴崳鈺漰pV7.7.1.910 鐎规ɑ鏌熼張鈧弬鎵QQ闂冨懓顕伴崳鈺漰pV7.7.1.910 鐎规ɑ鏌熼張鈧弬鎵
閹虫帊姹夐悾鍛儔閸氼兛鍔焌ppv7.1.5 鐎规ɑ鏌熺€瑰宕滈悧锟�閹虫帊姹夐悾鍛儔閸氼兛鍔焌ppv7.1.5 鐎规ɑ鏌熺€瑰宕滈悧锟�
鐠ч鍋g拠璁冲姛app閺傛壆澧楅張锟�20227.9.186 鐎瑰宕滈悧锟�鐠ч鍋g拠璁冲姛app閺傛壆澧楅張锟�20227.9.186 鐎瑰宕滈悧锟�
闁叉垼鐎洪悶鍡氬偍
楠炲啿鐣ㄧ拠浣稿煖鐎瑰…閻炲棜鍌╒9.1.0.1 鐎规ɑ鏌熺€瑰宕滈悧锟�楠炲啿鐣ㄧ拠浣稿煖鐎瑰…閻炲棜鍌╒9.1.0.1 鐎规ɑ鏌熺€瑰宕滈悧锟�
濞寸兘鈧俺鐦夐崚鍛婂閺堣櫣澧�(e濞寸兘鈧俺鍌�)8.71 鐎规ɑ鏌熺€瑰宕滈悧锟�濞寸兘鈧俺鐦夐崚鍛婂閺堣櫣澧�(e濞寸兘鈧俺鍌�)8.71 鐎规ɑ鏌熺€瑰宕滈悧锟�
娑撴粍鎹g拠浣稿煖娑撴粍鎹i悶鍡氬偍4.0.5 鐎瑰宕滈悧锟�娑撴粍鎹g拠浣稿煖娑撴粍鎹i悶鍡氬偍4.0.5 鐎瑰宕滈悧锟�
娑擃參鎽辩拠浣稿煖缁夎濮╅悶鍡氬偍鏉烆垯娆�6.02.010 鐎规ɑ鏌熺€瑰宕滈悧锟�娑擃參鎽辩拠浣稿煖缁夎濮╅悶鍡氬偍鏉烆垯娆�6.02.010 鐎规ɑ鏌熺€瑰宕滈悧锟�
閸楀酣绶崇拠浣稿煖鐏忓繘鍣鹃幍瀣簚閻炲棜鍌ㄦ潪顖欐3.2.4 鐎瑰宕滈悧锟�閸楀酣绶崇拠浣稿煖鐏忓繘鍣鹃幍瀣簚閻炲棜鍌ㄦ潪顖欐3.2.4 鐎瑰宕滈悧锟�
閹靛婧€闁炬儼顢�
缁傚繐缂撻崘婊勬綑娣囷紕鏁ょ粈鐐閺堟椽鎽辩悰灞筋吂閹撮顏�2.3.4 鐎瑰宕滈悧锟�缁傚繐缂撻崘婊勬綑娣囷紕鏁ょ粈鐐閺堟椽鎽辩悰灞筋吂閹撮顏�2.3.4 鐎瑰宕滈悧锟�
閺勬挸鍩楁担婊嗩潒妫版垵澹€鏉堟叧pp4.1.16鐎瑰宕滈悧锟�閺勬挸鍩楁担婊嗩潒妫版垵澹€鏉堟叧pp4.1.16鐎瑰宕滈悧锟�
閺€顖欑帛鐎规繈鎸堕崠锟�(Alipay)V10.2.53.7000 鐎瑰宕滈悧锟�閺€顖欑帛鐎规繈鎸堕崠锟�(Alipay)V10.2.53.7000 鐎瑰宕滈悧锟�
娑擃厼娴楀銉ユ櫌闁炬儼顢戦幍瀣簚闁炬儼顢慳ppV7.0.1.2.5 鐎瑰宕滈悧锟�娑擃厼娴楀銉ユ櫌闁炬儼顢戦幍瀣簚闁炬儼顢慳ppV7.0.1.2.5 鐎瑰宕滈悧锟�
娑擃厼娴楅柧鎯邦攽閹靛婧€闁炬儼顢戠€广垺鍩涚粩锟�7.2.5 鐎规ɑ鏌熺€瑰宕滈悧锟�娑擃厼娴楅柧鎯邦攽閹靛婧€闁炬儼顢戠€广垺鍩涚粩锟�7.2.5 鐎规ɑ鏌熺€瑰宕滈悧锟�
娴兼垿妫介惄濠冩
閼垫崘顔嗛悮搴ㄥ鏉堝彞姹夐幍瀣簚閻楀湸2.3.0.0 鐎规ɑ鏌熺€瑰宕滈悧锟�閼垫崘顔嗛悮搴ㄥ鏉堝彞姹夐幍瀣簚閻楀湸2.3.0.0 鐎规ɑ鏌熺€瑰宕滈悧锟�
閸旇尪鍨堕崶銏犵暭閺傝顒滈悧鍫熷濞撶1.2.1鐎规ɑ鏌熼悧锟�閸旇尪鍨堕崶銏犵暭閺傝顒滈悧鍫熷濞撶1.2.1鐎规ɑ鏌熼悧锟�
妤椼儵銈挎ご銊╁鏉╂稑瀵查弮鐘绘闁借崵鐓堕悧鍧�7.8.0.0鐎瑰宕滈悧锟�妤椼儵銈挎ご銊╁鏉╂稑瀵查弮鐘绘闁借崵鐓堕悧鍧�7.8.0.0鐎瑰宕滈悧锟�
濡炲秶澧挎径褎鍨崓闈涙閸忋劍妲戦弰锟�1.0.91 鐎瑰宕滈悧锟�濡炲秶澧挎径褎鍨崓闈涙閸忋劍妲戦弰锟�1.0.91 鐎瑰宕滈悧锟�
閸斻劋缍旂亸鍕毊
閸﹂绗呴崺搴g崐閸戞槒鈧崑t閻楋拷1.6.3 鐎规ɑ鏌熼悧锟�閸﹂绗呴崺搴g崐閸戞槒鈧崑t閻楋拷1.6.3 鐎规ɑ鏌熼悧锟�
鐟佸懐鏁抽懕鏃傛礃1.325.157 鐎瑰宕滈悧锟�鐟佸懐鏁抽懕鏃傛礃1.325.157 鐎瑰宕滈悧锟�
閸︼絾鏋熸竟顐fЕ閻垽娉︾紒鎼�4.2.1 鐎瑰宕滈悧锟�閸︼絾鏋熸竟顐fЕ閻垽娉︾紒鎼�4.2.1 鐎瑰宕滈悧锟�
闁喖銇�3D閹靛鐖�1.0.9鐎瑰宕滈悧锟�闁喖銇�3D閹靛鐖�1.0.9鐎瑰宕滈悧锟�
婵夋棃妲诲〒鍛婂灆
鐎瑰宕滃宥囧⒖婢堆勫灛閸嶉潧妗�2姒涙垶娈弮鏈靛敩娣囶喗鏁奸悧鍦�1.9.5 閺堚偓閺傛壆澧�鐎瑰宕滃宥囧⒖婢堆勫灛閸嶉潧妗�2姒涙垶娈弮鏈靛敩娣囶喗鏁奸悧鍦�1.9.5 閺堚偓閺傛壆澧�
娑旇鲸鏋熺憲鎸庣埗2v1.0.150鐎瑰宕滈悧锟�娑旇鲸鏋熺憲鎸庣埗2v1.0.150鐎瑰宕滈悧锟�
娣囨繂宕奸拃婵嗗椽3閺冪娀妾洪柦鑽ょ叾閺堚偓閺傛壆澧梫2.0.0.1 鐎瑰宕滈悧锟�娣囨繂宕奸拃婵嗗椽3閺冪娀妾洪柦鑽ょ叾閺堚偓閺傛壆澧梫2.0.0.1 鐎瑰宕滈悧锟�
閸欙綀顣伴懟閬嶆碂閸楁洘婧€閻楋拷1.2.0 鐎瑰宕滈悧锟�閸欙綀顣伴懟閬嶆碂閸楁洘婧€閻楋拷1.2.0 鐎瑰宕滈悧锟�
鐏忓繐鐨崘娑樻礋鐎瑰宕滈悧锟�2.7.4 閺冪娀妾洪柌鎴濈娣囶喗鏁奸悧锟�鐏忓繐鐨崘娑樻礋鐎瑰宕滈悧锟�2.7.4 閺冪娀妾洪柌鎴濈娣囶喗鏁奸悧锟�
鐠ф稖婧呯粩鐐村Η
閻ц鍖楃挧娑滄簠2閹靛鐖�1.47.1  鐎瑰宕滈悧锟�閻ц鍖楃挧娑滄簠2閹靛鐖�1.47.1 鐎瑰宕滈悧锟�
娑撯偓鐠ч攱娼垫鐐舵簠鐎瑰宕滈悧鍧�2.9.14 閺堚偓閺傛壆澧�娑撯偓鐠ч攱娼垫鐐舵簠鐎瑰宕滈悧鍧�2.9.14 閺堚偓閺傛壆澧�
鐠烘垼绐囬崡鈥茬鏉烇附澧滈張铏瑰鐎规ɑ鏌熼張鈧弬鎵v1.16.2 鐎瑰宕滈悧锟�鐠烘垼绐囬崡鈥茬鏉烇附澧滈張铏瑰鐎规ɑ鏌熼張鈧弬鎵v1.16.2 鐎瑰宕滈悧锟�
閻欏倿鍣规娆掓簠8閺嬩線鈧喎鍣锋禍鎴滄叏閺€鍦(閸忓秵鏆熼幑顔煎瘶)v4.6.0j 闁叉垵绔甸弮鐘绘閻楋拷閻欏倿鍣规娆掓簠8閺嬩線鈧喎鍣锋禍鎴滄叏閺€鍦(閸忓秵鏆熼幑顔煎瘶)v4.6.0j 闁叉垵绔甸弮鐘绘閻楋拷
閻у彞绠伴崡鍐仏閹规洟濂�2021閺堚偓閺傛壆澧�5.78 鐎瑰宕滈悧锟�閻у彞绠伴崡鍐仏閹规洟濂�2021閺堚偓閺傛壆澧�5.78 鐎瑰宕滈悧锟�
鐟欐帟澹婇幍顔界川
濮婏箑澶熼崜鎴e灦閼板懎褰夐幀浣哄1.0.1.2鐎瑰宕滈悧锟�濮婏箑澶熼崜鎴e灦閼板懎褰夐幀浣哄1.0.1.2鐎瑰宕滈悧锟�
娴犳瑥顣ㄦ导鐘侯嚛ro婢跺秴鍙寸€瑰宕滈悧锟�1.20.3閺堚偓閺傛壆澧�娴犳瑥顣ㄦ导鐘侯嚛ro婢跺秴鍙寸€瑰宕滈悧锟�1.20.3閺堚偓閺傛壆澧�
濮婏箑澶熺拠娑楃舶閹靛鐖堕悧锟�1.3.6 鐎规ɑ鏌熺€瑰宕滈悧锟�濮婏箑澶熺拠娑楃舶閹靛鐖堕悧锟�1.3.6 鐎规ɑ鏌熺€瑰宕滈悧锟�
閻滃鈧懓宕抽懓鈧琕3.72.1.1 鐎瑰宕滈張鈧弬鏉跨暭閺傚湱澧�閻滃鈧懓宕抽懓鈧琕3.72.1.1 鐎瑰宕滈張鈧弬鏉跨暭閺傚湱澧�
鐠嬩礁顔嶇亸蹇氭簠瀵儤澧滈張铏瑰v1.0.49 鐎瑰宕滈悧锟�鐠嬩礁顔嶇亸蹇氭簠瀵儤澧滈張铏瑰v1.0.49 鐎瑰宕滈悧锟�
缁崵绮烘潪顖欐
mac绾句胶娲忛崚鍡楀隘瀹搞儱鍙�(Paragon Camptune X)V10.8.12鐎规ɑ鏌熼張鈧弬鎵mac绾句胶娲忛崚鍡楀隘瀹搞儱鍙�(Paragon Camptune X)V10.8.12鐎规ɑ鏌熼張鈧弬鎵
閼昏鐏夐幙宥勭稊缁崵绮篗ACOSX 10.9.4 Mavericks鐎瑰苯鍙忛崗宥堝瀭閻楋拷閼昏鐏夐幙宥勭稊缁崵绮篗ACOSX 10.9.4 Mavericks鐎瑰苯鍙忛崗宥堝瀭閻楋拷
Rar鐟欙絽甯囬崚鈺佹珤mac閻楀澊1.4 鐎规ɑ鏌熼崗宥堝瀭閻楋拷Rar鐟欙絽甯囬崚鈺佹珤mac閻楀澊1.4 鐎规ɑ鏌熼崗宥堝瀭閻楋拷
Mac鐎瑰宕滃Ο鈩冨珯閸o拷(ARC Welder)v1.0 鐎规ɑ鏌熼張鈧弬鎵Mac鐎瑰宕滃Ο鈩冨珯閸o拷(ARC Welder)v1.0 鐎规ɑ鏌熼張鈧弬鎵
Charles for MacV3.9.3鐎规ɑ鏌熼悧锟�Charles for MacV3.9.3鐎规ɑ鏌熼悧锟�
缂冩垹绮跺銉ュ徔
閹兼粎瀚嶅ù蹇氼潔閸b暕ac閻楀澊5.2 鐎规ɑ鏌熷锝呯础閻楋拷閹兼粎瀚嶅ù蹇氼潔閸b暕ac閻楀澊5.2 鐎规ɑ鏌熷锝呯础閻楋拷
闁挎劖宓庣€广垺鍩涚粩鐥琣c閻楀湸1.33鐎规ɑ鏌熼張鈧弬鎵闁挎劖宓庣€广垺鍩涚粩鐥琣c閻楀湸1.33鐎规ɑ鏌熼張鈧弬鎵
韫囶偆澧甿ac閻楀澊1.3.2 鐎规ɑ鏌熷锝呯础閻楋拷韫囶偆澧甿ac閻楀澊1.3.2 鐎规ɑ鏌熷锝呯础閻楋拷
閺嬩胶鍋f禍鏃傜應Mac閻楋拷7.13濮濓絽绱¢悧锟�閺嬩胶鍋f禍鏃傜應Mac閻楋拷7.13濮濓絽绱¢悧锟�
婵帊缍嬪銉ュ徔
Apple Logic Pro xV10.3.2Apple Logic Pro xV10.3.2
Adobe Premiere Pro CC 2017 mac閻楀澊11.0.0 娑擃厽鏋冮悧锟�Adobe Premiere Pro CC 2017 mac閻楀澊11.0.0 娑擃厽鏋冮悧锟�
閸楀啫宕堥棃娆忔儔Mac閻楀湸9.1.1 鐎规ɑ鏌熼張鈧弬鎵閸楀啫宕堥棃娆忔儔Mac閻楀湸9.1.1 鐎规ɑ鏌熼張鈧弬鎵
Mac缂冩垹绮堕惄瀛樻尡鏉烆垯娆�(MacTV)v0.121 鐎规ɑ鏌熼張鈧弬鎵Mac缂冩垹绮堕惄瀛樻尡鏉烆垯娆�(MacTV)v0.121 鐎规ɑ鏌熼張鈧弬鎵
Adobe Fireworks CS6 Mac閻楀湑S6鐎规ɑ鏌熺粻鈧担鎾茶厬閺傚洨澧�Adobe Fireworks CS6 Mac閻楀湑S6鐎规ɑ鏌熺粻鈧担鎾茶厬閺傚洨澧�
閸ユ儳鑸伴崶鎯у剼
AutoCAD2015 mac娑擃厽鏋冮悧鍫熸拱v1.0 鐎规ɑ鏌熷锝呯础閻楋拷AutoCAD2015 mac娑擃厽鏋冮悧鍫熸拱v1.0 鐎规ɑ鏌熷锝呯础閻楋拷
Adobe Photoshop cs6 mac閻楀澊13.0.3 鐎规ɑ鏌熸稉顓熸瀮閻楋拷Adobe Photoshop cs6 mac閻楀澊13.0.3 鐎规ɑ鏌熸稉顓熸瀮閻楋拷
Mac閻垽鍣虹紒妯烘禈鏉烆垯娆�(Sketch mac)v3.3.2 娑擃厽鏋冮悧锟�Mac閻垽鍣虹紒妯烘禈鏉烆垯娆�(Sketch mac)v3.3.2 娑擃厽鏋冮悧锟�
Adobe After Effects cs6 mac閻楀澊1.0娑擃厽鏋冮悧锟�Adobe After Effects cs6 mac閻楀澊1.0娑擃厽鏋冮悧锟�
Adobe InDesign cs6 mac1.0 鐎规ɑ鏌熸稉顓熸瀮閻楋拷Adobe InDesign cs6 mac1.0 鐎规ɑ鏌熸稉顓熸瀮閻楋拷
鎼存梻鏁ゆ潪顖欐
Mac閻楀牆鎻╅幘锟�1.1.26 鐎规ɑ鏌熷锝呯础閻楀溂dmg]Mac閻楀牆鎻╅幘锟�1.1.26 鐎规ɑ鏌熷锝呯础閻楀溂dmg]
Mac鐠囪鍟揘TFS(Paragon NTFS for Mac)12.1.62 鐎规ɑ鏌熷锝呯础閻楋拷Mac鐠囪鍟揘TFS(Paragon NTFS for Mac)12.1.62 鐎规ɑ鏌熷锝呯础閻楋拷
鏉╁懘娴�10 for macv3.4.1.4368 鐎规ɑ鏌熼張鈧弬鎵鏉╁懘娴�10 for macv3.4.1.4368 鐎规ɑ鏌熼張鈧弬鎵
Mac娑撳娓跺鍝勩亣閻ㄥ嫮閮寸紒鐔哥閻炲棗浼愰崗锟�(CleanMyMac for mac)v3.1.1 濮濓絽绱¢悧锟�Mac娑撳娓跺鍝勩亣閻ㄥ嫮閮寸紒鐔哥閻炲棗浼愰崗锟�(CleanMyMac for mac)v3.1.1 濮濓絽绱¢悧锟�
閼昏鐏塀ootCamp5.1.5640 鐎规ɑ鏌熼張鈧弬鎵閼昏鐏塀ootCamp5.1.5640 鐎规ɑ鏌熼張鈧弬鎵
ios缁€鍙ユ唉閼卞﹤銇�
瀵邦喕淇奿pad閻楋拷2020v7.0.12 鐎规ɑ鏌熼悧锟�瀵邦喕淇奿pad閻楋拷2020v7.0.12 鐎规ɑ鏌熼悧锟�
iphone閹靛婧€qq2021v8.5.0 鐎规ɑ鏌熼悧锟�iphone閹靛婧€qq2021v8.5.0 鐎规ɑ鏌熼悧锟�
閺勬挷淇奿OS閻楀澊7.3.13 iPhone閻楋拷閺勬挷淇奿OS閻楀澊7.3.13 iPhone閻楋拷
闂勫矂妾� iphoneV8.32.4 鐎规ɑ鏌熷锝呯础閻楋拷闂勫矂妾� iphoneV8.32.4 鐎规ɑ鏌熷锝呯础閻楋拷
閸楀啰澧� iphone閻楋拷9.2.5 鐎规ɑ鏌熼悧锟�閸楀啰澧� iphone閻楋拷9.2.5 鐎规ɑ鏌熼悧锟�
ios閻㈢喐妞块張宥呭
99娑撱儵鈧娓堕弬鎵V1.3.699娑撱儵鈧娓堕弬鎵V1.3.6
韫囶偆澧甶Phone閻楋拷5.7.3 鐎规ɑ鏌熼悧锟�韫囶偆澧甶Phone閻楋拷5.7.3 鐎规ɑ鏌熼悧锟�
濞fê鐤� for iPhonev9.5.15 鐎规ɑ鏌熼張鈧弬鎵濞fê鐤� for iPhonev9.5.15 鐎规ɑ鏌熼張鈧弬鎵
婢с劏鎶楁径鈺傜毜 for iphoneV7.5.3鐎规ɑ鏌熼張鈧弬鎵IPA婢с劏鎶楁径鈺傜毜 for iphoneV7.5.3鐎规ɑ鏌熼張鈧弬鎵IPA
鐠嬮攱鐡曢崷鏉挎禈iphone(Google Maps)4.54  娑擃厽鏋冮悧锟�鐠嬮攱鐡曢崷鏉挎禈iphone(Google Maps)4.54 娑擃厽鏋冮悧锟�
ios瑜伴亶鐓舵繛鍙樼
韫囶偅鎸遍懟瑙勭亯閻楀湸3.3.35 鐎规ɑ鏌熼悧鍦糹pa]韫囶偅鎸遍懟瑙勭亯閻楀湸3.3.35 鐎规ɑ鏌熼悧鍦糹pa]
閸氬鎮忚ぐ閬嶇叾閹绢厽鏂侀崳鈺s閻楋拷1.0.1017 閼昏鐏塱pad閻楋拷閸氬鎮忚ぐ閬嶇叾閹绢厽鏂侀崳鈺s閻楋拷1.0.1017 閼昏鐏塱pad閻楋拷
瑜伴亶鐓堕崗鍫ユ敱閹绢厽鏂侀崳鈺s閻楋拷2.8.0 鐎规ɑ鏌熼悧锟�瑜伴亶鐓堕崗鍫ユ敱閹绢厽鏂侀崳鈺s閻楋拷2.8.0 鐎规ɑ鏌熼悧锟�
閺傛濂旈惄瀛樻尡鐎广垺鍩涚粩鐥爋s閻楋拷7.0.1 鐎规ɑ鏌熼張鈧弬鎵閺傛濂旈惄瀛樻尡鐎广垺鍩涚粩鐥爋s閻楋拷7.0.1 鐎规ɑ鏌熼張鈧弬鎵
闁伴瀚嶉棅鍏呯 for iPhonev10.9.0 鐎规ɑ鏌熼張鈧弬鎵闁伴瀚嶉棅鍏呯 for iPhonev10.9.0 鐎规ɑ鏌熼張鈧弬鎵
ios閸ユ儳鑸伴崶鎯у剼
How old do I look ios閻楋拷1.02 鐎规ɑ鏌熼悧锟�How old do I look ios閻楋拷1.02 鐎规ɑ鏌熼悧锟�
缂囧骸娴樼粔鈧粔鈧琲Phone閻楀湸8.6.62 閺堚偓閺傜増顒滃蹇曞缂囧骸娴樼粔鈧粔鈧琲Phone閻楀湸8.6.62 閺堚偓閺傜増顒滃蹇曞
濮樻潙宓冮梼鐔兼毐閼昏鐏夐悧鍧�1.0.0濮樻潙宓冮梼鐔兼毐閼昏鐏夐悧鍧�1.0.0
婢垛晛銇塸閸ョ穭pad閻楋拷5.7.4 鐎规ɑ鏌熼悧锟�婢垛晛銇塸閸ョ穭pad閻楋拷5.7.4 鐎规ɑ鏌熼悧锟�
韫囶偅澧渋os閻楀湸9.6.30 鐎规ɑ鏌熼悧锟�韫囶偅澧渋os閻楀湸9.6.30 鐎规ɑ鏌熼悧锟�
ios濞村繗顫嶅銉ュ徔
閼冲苯瀵橀崷鏉挎禈ios閻楋拷1.0 鐎规ɑ鏌熼張鈧弬鎵閼冲苯瀵橀崷鏉挎禈ios閻楋拷1.0 鐎规ɑ鏌熼張鈧弬鎵
閹靛婧€鐎瑰鍙忛崝鈺傚閼昏鐏夐悧鍧�1.0 鐎规ɑ鏌熼張鈧弬鎵閹靛婧€鐎瑰鍙忛崝鈺傚閼昏鐏夐悧鍧�1.0 鐎规ɑ鏌熼張鈧弬鎵
UC濞村繗顫嶉崳鈺�113.5.5.1555娑擃厽鏋冮悧锟�UC濞村繗顫嶉崳鈺�113.5.5.1555娑擃厽鏋冮悧锟�
360濞村繗顫嶉崳鈩塂 for iPadV4.1.3  濮濓絽绱¢悧锟�360濞村繗顫嶉崳鈩塂 for iPadV4.1.3 濮濓絽绱¢悧锟�
iPhone閹靛婧€QQ濞村繗顫嶉崳鈺�8.9.1 鐎规ɑ鏌熼悧锟�iPhone閹靛婧€QQ濞村繗顫嶉崳鈺�8.9.1 鐎规ɑ鏌熼悧锟�

首页编程开发Delphi → Delphi实现的线程池代码单元

Delphi实现的线程池代码单元

相关文章发表评论 来源:西西整理时间:2012/12/6 11:26:43字体大小:A-A+

作者:lucasli点击:0次评论:0次标签: 线程

  • 类型:服务器区大小:21KB语言:中文 评分:6.6
  • 标签:
立即下载
Delphi">Delphi什么样的线程池更好呢?我觉得使用起来要可靠,并且一定要简单,这样才是更好的。我写的线程池就是这样一个标准,使用非常简单,只传入自己要执行的方法就可以了,其实大家最后就是关注自己要操作的方法,其余的交给线程池。
unit uThreadPool;

{   aPool.AddRequest(TMyRequest.Create(RequestParam1, RequestParam2, ...)); }

interface
uses
  Windows,
  Classes;

// 是否记录日志
// {$DEFINE NOLOGS}

type
  TCriticalSection = class(TObject)
  protected
    FSection: TRTLCriticalSection;
  public
    constructor Create;
    destructor Destroy; override;
    // 进入临界区
    procedure Enter;
    // 离开临界区
    procedure Leave;
    // 尝试进入
    function TryEnter: Boolean;
  end;

type
  // 储存请求数据的基本类
  TWorkItem = class(TObject)
  public
    // 是否有重复任务
    function IsTheSame(DataObj: TWorkItem): Boolean; virtual;
    // 如果 NOLOGS 被定义,则禁用。
    function TextForLog: string; virtual;
  end;

type
  TThreadsPool = class;

  //线程状态
  TThreadState = (tcsInitializing, tcsWaiting, tcsGetting, tcsProcessing,
    tcsProcessed, tcsTerminating, tcsCheckingDown);
  // 工作线程仅用于线程池内, 不要直接创建并调用它。
  TProcessorThread = class(TThread)
  private
    // 创建线程时临时的Event对象, 阻塞线程直到初始化完成
    hInitFinished: THandle;
    // 初始化出错信息
    sInitError: string;
    // 记录日志
    procedure WriteLog(const Str: string; Level: Integer = 0);
  protected
    // 线程临界区同步对像
    csProcessingDataObject: TCriticalSection;
    // 平均处理时间
    FAverageProcessing: Integer;
    // 等待请求的平均时间
    FAverageWaitingTime: Integer;
    // 本线程实例的运行状态
    FCurState: TThreadState;
    // 本线程实例所附属的线程池
    FPool: TThreadsPool;
    // 当前处理的数据对像。
    FProcessingDataObject: TWorkItem;
    // 线程停止 Event, TProcessorThread.Terminate 中开绿灯
    hThreadTerminated: THandle;
    uProcessingStart: DWORD;
    // 开始等待的时间, 通过 GetTickCount 取得。
    uWaitingStart: DWORD;
    // 计算平均工作时间
    function AverageProcessingTime: DWORD;
    // 计算平均等待时间
    function AverageWaitingTime: DWORD;
    procedure Execute; override;
    function IamCurrentlyProcess(DataObj: TWorkItem): Boolean;
    // 转换枚举类型的线程状态为字串类型
    function InfoText: string;
    // 线程是否长时间处理同一个请求?(已死掉?)
    function IsDead: Boolean;
    // 线程是否已完成当成任务
    function isFinished: Boolean;
    // 线程是否处于空闲状态
    function isIdle: Boolean;
    // 平均值校正计算。
    function NewAverage(OldAvg, NewVal: Integer): Integer;
  public
    Tag: Integer;
    constructor Create(APool: TThreadsPool);
    destructor Destroy; override;
    procedure Terminate;
  end;

  // 线程初始化时触发的事件
  TProcessorThreadInitializing = procedure(Sender: TThreadsPool; aThread:
    TProcessorThread) of object;
  // 线程结束时触发的事件
  TProcessorThreadFinalizing = procedure(Sender: TThreadsPool; aThread:
    TProcessorThread) of object;
  // 线程处理请求时触发的事件
  TProcessRequest = procedure(Sender: TThreadsPool; WorkItem: TWorkItem;
    aThread: TProcessorThread) of object;
  TEmptyKind = (
    ekQueueEmpty, //任务被取空后
    ekProcessingFinished // 最后一个任务处理完毕后
    );
  // 任务队列空时触发的事件
  TQueueEmpty = procedure(Sender: TThreadsPool; EmptyKind: TEmptyKind) of
    object;

  TThreadsPool = class(TComponent)
  private
    csQueueManagment: TCriticalSection;
    csThreadManagment: TCriticalSection;
    FProcessRequest: TProcessRequest;
    FQueue: TList;
    FQueueEmpty: TQueueEmpty;
    // 线程超时阀值
    FThreadDeadTimeout: DWORD;
    FThreadFinalizing: TProcessorThreadFinalizing;
    FThreadInitializing: TProcessorThreadInitializing;
    // 工作中的线程
    FThreads: TList;
    // 执行了 terminat 发送退出指令, 正在结束的线程.
    FThreadsKilling: TList;
    // 最少, 最大线程数
    FThreadsMax: Integer;
    // 最少, 最大线程数
    FThreadsMin: Integer;
    // 池平均等待时间
    function PoolAverageWaitingTime: Integer;
    procedure WriteLog(const Str: string; Level: Integer = 0);
  protected
    FLastGetPoint: Integer;
    // Semaphore, 统计任务队列
    hSemRequestCount: THandle;
    // Waitable timer. 每30触发一次的时间量同步
    hTimCheckPoolDown: THandle;
    // 线程池停机(检查并清除空闲线程和死线程)
    procedure CheckPoolDown;
    // 清除死线程,并补充不足的工作线程
    procedure CheckThreadsForGrow;
    procedure DoProcessed;
    procedure DoProcessRequest(aDataObj: TWorkItem; aThread: TProcessorThread);
      virtual;
    procedure DoQueueEmpty(EmptyKind: TEmptyKind); virtual;
    procedure DoThreadFinalizing(aThread: TProcessorThread); virtual;
    // 执行事件
    procedure DoThreadInitializing(aThread: TProcessorThread); virtual;
    // 释放 FThreadsKilling 列表中的线程
    procedure FreeFinishedThreads;
    // 申请任务
    procedure GetRequest(out Request: TWorkItem);
    // 清除死线程
    procedure KillDeadThreads;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    // 就进行任务是否重复的检查, 检查发现重复就返回 False
    function AddRequest(aDataObject: TWorkItem; CheckForDoubles: Boolean =
      False): Boolean; overload;
    // 转换枚举类型的线程状态为字串类型
    function InfoText: string;
  published
    // 线程处理任务时触发的事件
    property OnProcessRequest: TProcessRequest read FProcessRequest write
      FProcessRequest;
    // 任务列表为空时解发的事件
    property OnQueueEmpty: TQueueEmpty read FQueueEmpty write FQueueEmpty;
    // 线程结束时触发的事件
    property OnThreadFinalizing: TProcessorThreadFinalizing read
      FThreadFinalizing write FThreadFinalizing;
    // 线程初始化时触发的事件
    property OnThreadInitializing: TProcessorThreadInitializing read
      FThreadInitializing write FThreadInitializing;
    // 线程超时值(毫秒), 如果处理超时,将视为死线程
    property ThreadDeadTimeout: DWORD read FThreadDeadTimeout write
      FThreadDeadTimeout default 0;
    // 最大线程数
    property ThreadsMax: Integer read FThreadsMax write FThreadsMax default 1;
    // 最小线程数
    property ThreadsMin: Integer read FThreadsMin write FThreadsMin default 0;
  end;

type
  //日志记志函数
  TLogWriteProc = procedure(
    const Str: string; //日志
    LogID: Integer = 0;
    Level: Integer = 0 //Level = 0 - 跟踪信息, 10 - 致命错误
    );

var
  WriteLog: TLogWriteProc; // 如果存在实例就写日志

implementation
uses
  SysUtils;

// 储存请求数据的基本类
{
********************************** TWorkItem ***********************************
}

function TWorkItem.IsTheSame(DataObj: TWorkItem): Boolean;
begin
  Result := False;
end; { TWorkItem.IsTheSame }

function TWorkItem.TextForLog: string;
begin
  Result := 'Request';
end; { TWorkItem.TextForLog }

{
********************************* TThreadsPool *********************************
}

constructor TThreadsPool.Create(AOwner: TComponent);
var
  DueTo: Int64;
begin
{$IFNDEF NOLOGS}
  WriteLog('创建线程池', 5);
{$ENDIF}
  inherited;
  csQueueManagment := TCriticalSection.Create;
  FQueue := TList.Create;
  csThreadManagment := TCriticalSection.Create;
  FThreads := TList.Create;
  FThreadsKilling := TList.Create;
  FThreadsMin := 0;
  FThreadsMax := 1;
  FThreadDeadTimeout := 0;
  FLastGetPoint := 0;
  //
  hSemRequestCount := CreateSemaphore(nil, 0, $7FFFFFFF, nil);

  DueTo := -1;
  //可等待的定时器(只用于Window NT4或更高)
  hTimCheckPoolDown := CreateWaitableTimer(nil, False, nil);

  if hTimCheckPoolDown = 0 then // Win9x不支持
    // In Win9x number of thread will be never decrised
    hTimCheckPoolDown := CreateEvent(nil, False, False, nil)
  else
    SetWaitableTimer(hTimCheckPoolDown, DueTo, 30000, nil, nil, False);
end; { TThreadsPool.Create }

destructor TThreadsPool.Destroy;
var
  n, i: Integer;
  Handles: array of THandle;
begin
{$IFNDEF NOLOGS}
  WriteLog('线程池销毁', 5);
{$ENDIF}
  csThreadManagment.Enter;

  SetLength(Handles, FThreads.Count);
  n := 0;
  for i := 0 to FThreads.Count - 1 do
    if FThreads[i] <> nil then
    begin
      Handles[n] := TProcessorThread(FThreads[i]).Handle;
      TProcessorThread(FThreads[i]).Terminate;
      Inc(n);
    end;

  csThreadManagment.Leave;  // lixiaoyu 添加于 2009.1.6,如没有此行代码无法成功释放正在执行中的工作者线程,死锁。

  WaitForMultipleObjects(n, @Handles[0], True, 30000);  // 等待工作者线程执行终止  lixiaoyu 注释于 2009.1.6

  csThreadManagment.Enter;  // lixiaoyu 添加于 2009.1.6 再次进入锁定,并释放资源
  for i := 0 to FThreads.Count - 1 do
    TProcessorThread(FThreads[i]).Free;
  FThreads.Free;
  FThreadsKilling.Free;
  csThreadManagment.Free;

  csQueueManagment.Enter;
  for i := FQueue.Count - 1 downto 0 do
    TObject(FQueue[i]).Free;
  FQueue.Free;
  csQueueManagment.Free;

  CloseHandle(hSemRequestCount);
  CloseHandle(hTimCheckPoolDown);
  inherited;
end; { TThreadsPool.Destroy }

function TThreadsPool.AddRequest(aDataObject: TWorkItem; CheckForDoubles:
  Boolean = False): Boolean;
var
  i: Integer;
begin
{$IFNDEF NOLOGS}
  WriteLog('AddRequest(' + aDataObject.TextForLog + ')', 2);
{$ENDIF}
  Result := False;
  csQueueManagment.Enter;
  try
    // 如果 CheckForDoubles = TRUE
    // 则进行任务是否重复的检查
    if CheckForDoubles then
      for i := 0 to FQueue.Count - 1 do
        if (FQueue[i] <> nil)
          and aDataObject.IsTheSame(TWorkItem(FQueue[i])) then
          Exit; // 发现有相同的任务

    csThreadManagment.Enter;
    try
      // 清除死线程,并补充不足的工作线程
      CheckThreadsForGrow;

      // 如果 CheckForDoubles = TRUE
      // 则检查是否有相同的任务正在处理中
      if CheckForDoubles then
        for i := 0 to FThreads.Count - 1 do
          if TProcessorThread(FThreads[i]).IamCurrentlyProcess(aDataObject) then
            Exit; // 发现有相同的任务

    finally
      csThreadManagment.Leave;
    end;

    //将任务加入队列
    FQueue.Add(aDataObject);

    //释放一个同步信号量
    ReleaseSemaphore(hSemRequestCount, 1, nil);
{$IFNDEF NOLOGS}
    WriteLog('释放一个同步信号量)', 1);
{$ENDIF}
    Result := True;
  finally
    csQueueManagment.Leave;
  end;
{$IFNDEF NOLOGS}
  //调试信息
  WriteLog('增加一个任务(' + aDataObject.TextForLog + ')', 1);
{$ENDIF}
end; { TThreadsPool.AddRequest }

{
  名:TThreadsPool.CheckPoolDown
功能描述:线程池停机(检查并清除空闲线程和死线程)
输入参数:无
  值: 
创建日期:2006.10.22 11:31
修改日期:2006.
    者:Kook
附加说明:
}

procedure TThreadsPool.CheckPoolDown;
var
  i: Integer;
begin
{$IFNDEF NOLOGS}
  WriteLog('TThreadsPool.CheckPoolDown', 1);
{$ENDIF}
  csThreadManagment.Enter;
  try
{$IFNDEF NOLOGS}
    WriteLog(InfoText, 2);
{$ENDIF}
    // 清除死线程
    KillDeadThreads;
    // 释放 FThreadsKilling 列表中的线程
    FreeFinishedThreads;

    // 如果线程空闲,就终止它
    for i := FThreads.Count - 1 downto FThreadsMin do
      if TProcessorThread(FThreads[i]).isIdle then
      begin
        //发出终止命令
        TProcessorThread(FThreads[i]).Terminate;
        //加入待清除队列
        FThreadsKilling.Add(FThreads[i]);
        //从工作队列中除名
        FThreads.Delete(i);
        //todo: ??
        Break;
      end;
  finally
    csThreadManagment.Leave;
  end;
end; { TThreadsPool.CheckPoolDown }

{
  名:TThreadsPool.CheckThreadsForGrow
功能描述:清除死线程,并补充不足的工作线程
输入参数:无
  值: 
创建日期:2006.10.22 11:31
修改日期:2006.
    者:Kook
附加说明:
}

procedure TThreadsPool.CheckThreadsForGrow;
var
  AvgWait: Integer;
  i: Integer;
begin
  {
    New thread created if:
    新建线程的条件:
      1. 工作线程数小于最小线程数
      2. 工作线程数小于最大线程数 and 线程池平均等待时间 < 100ms(系统忙)
      3. 任务大于工作线程数的4
  }

  csThreadManagment.Enter;
  try
    KillDeadThreads;
    if FThreads.Count < FThreadsMin then
    begin
{$IFNDEF NOLOGS}
      WriteLog('工作线程数小于最小线程数', 4);
{$ENDIF}
      for i := FThreads.Count to FThreadsMin - 1 do
      try
        FThreads.Add(TProcessorThread.Create(Self));
      except
        on e: Exception do

          WriteLog(
            'TProcessorThread.Create raise: ' + e.ClassName + #13#10#9'Message: '
            + e.Message,
            9
            );
      end
    end
    else if FThreads.Count < FThreadsMax then
    begin
{$IFNDEF NOLOGS}
      WriteLog('工作线程数小于最大线程数 and 线程池平均等待时间 < 100ms', 3);
{$ENDIF}
      AvgWait := PoolAverageWaitingTime;
{$IFNDEF NOLOGS}
      WriteLog(Format(
        'FThreads.Count (%d)<FThreadsMax(%d), AvgWait=%d',
        [FThreads.Count, FThreadsMax, AvgWait]),
        4
        );
{$ENDIF}

      if AvgWait < 100 then
      try
        FThreads.Add(TProcessorThread.Create(Self));
      except
        on e: Exception do
          WriteLog(
            'TProcessorThread.Create raise: ' + e.ClassName +
            #13#10#9'Message: ' + e.Message,
            9
            );
      end;
    end;
  finally
    csThreadManagment.Leave;
  end;
end; { TThreadsPool.CheckThreadsForGrow }

procedure TThreadsPool.DoProcessed;
var
  i: Integer;
begin
  if (FLastGetPoint < FQueue.Count) then
    Exit;
  csThreadManagment.Enter;
  try
    for i := 0 to FThreads.Count - 1 do
      if TProcessorThread(FThreads[i]).FCurState in [tcsProcessing] then
        Exit;
  finally
    csThreadManagment.Leave;
  end;
  DoQueueEmpty(ekProcessingFinished);
end; { TThreadsPool.DoProcessed }

procedure TThreadsPool.DoProcessRequest(aDataObj: TWorkItem; aThread:
  TProcessorThread);
begin
  if Assigned(FProcessRequest) then
    FProcessRequest(Self, aDataObj, aThread);
end; { TThreadsPool.DoProcessRequest }

procedure TThreadsPool.DoQueueEmpty(EmptyKind: TEmptyKind);
begin
  if Assigned(FQueueEmpty) then
    FQueueEmpty(Self, EmptyKind);
end; { TThreadsPool.DoQueueEmpty }

procedure TThreadsPool.DoThreadFinalizing(aThread: TProcessorThread);
begin
  if Assigned(FThreadFinalizing) then
    FThreadFinalizing(Self, aThread);
end; { TThreadsPool.DoThreadFinalizing }

procedure TThreadsPool.DoThreadInitializing(aThread: TProcessorThread);
begin
  if Assigned(FThreadInitializing) then
    FThreadInitializing(Self, aThread);
end; { TThreadsPool.DoThreadInitializing }

{
  名:TThreadsPool.FreeFinishedThreads
功能描述:释放 FThreadsKilling 列表中的线程
输入参数:无
  值: 
创建日期:2006.10.22 11:34
修改日期:2006.
    者:Kook
附加说明:
}

procedure TThreadsPool.FreeFinishedThreads;
var
  i: Integer;
begin
  if csThreadManagment.TryEnter then
  try
    for i := FThreadsKilling.Count - 1 downto 0 do
      if TProcessorThread(FThreadsKilling[i]).isFinished then
      begin
        TProcessorThread(FThreadsKilling[i]).Free;
        FThreadsKilling.Delete(i);
      end;
  finally
    csThreadManagment.Leave
  end;
end; { TThreadsPool.FreeFinishedThreads }

{
  名:TThreadsPool.GetRequest
功能描述:申请任务
输入参数:out Request: TRequestDataObject
  值: 
创建日期:2006.10.22 11:34
修改日期:2006.
    者:Kook
附加说明:
}

procedure TThreadsPool.GetRequest(out Request: TWorkItem);
begin
{$IFNDEF NOLOGS}
  WriteLog('申请任务', 2);
{$ENDIF}
  csQueueManagment.Enter;
  try
    //跳过空的队列元素
    while (FLastGetPoint < FQueue.Count) and (FQueue[FLastGetPoint] = nil) do
      Inc(FLastGetPoint);

    Assert(FLastGetPoint < FQueue.Count);
    //压缩队列,清除空元素
    if (FQueue.Count > 127) and (FLastGetPoint >= (3 * FQueue.Count) div 4) then
    begin
{$IFNDEF NOLOGS}
      WriteLog('FQueue.Pack', 1);
{$ENDIF}
      FQueue.Pack;
      FLastGetPoint := 0;
    end;

    Request := TWorkItem(FQueue[FLastGetPoint]);
    FQueue[FLastGetPoint] := nil;
    inc(FLastGetPoint);
    if (FLastGetPoint = FQueue.Count) then //如果队列中无任务
    begin

      DoQueueEmpty(ekQueueEmpty);
      FQueue.Clear;
      FLastGetPoint := 0;
    end;
  finally
    csQueueManagment.Leave;
  end;
end; { TThreadsPool.GetRequest }

function TThreadsPool.InfoText: string;
begin
  Result := '';
  //end;
  //{$ELSE}
  //var
  //  i: Integer;
  //begin
  //  csQueueManagment.Enter;
  //  csThreadManagment.Enter;
  //  try
  //    if (FThreads.Count = 0) and (FThreadsKilling.Count = 1) and
  //      TProcessorThread(FThreadsKilling[0]).isFinished then
  //      FreeFinishedThreads;
  //
  //    Result := Format(
  //      'Pool thread: Min=%d, Max=%d, WorkingThreadsCount=%d, TerminatedThreadCount=%d, QueueLength=%d'#13#10,
  //      [ThreadsMin, ThreadsMax, FThreads.Count, FThreadsKilling.Count,
  //      FQueue.Count]
  //        );
  //    if FThreads.Count > 0 then
  //      Result := Result + 'Working threads:'#13#10;
  //    for i := 0 to FThreads.Count - 1 do
  //      Result := Result + TProcessorThread(FThreads[i]).InfoText + #13#10;
  //    if FThreadsKilling.Count > 0 then
  //      Result := Result + 'Terminated threads:'#13#10;
  //    for i := 0 to FThreadsKilling.Count - 1 do
  //      Result := Result + TProcessorThread(FThreadsKilling[i]).InfoText + #13#10;
  //  finally
  //    csThreadManagment.Leave;
  //    csQueueManagment.Leave;
  //  end;
  //end;
  //{$ENDIF}
end; { TThreadsPool.InfoText }

{
  名:TThreadsPool.KillDeadThreads
功能描述:清除死线程
输入参数:无
  值: 
创建日期:2006.10.22 11:32
修改日期:2006.
    者:Kook
附加说明:
}

procedure TThreadsPool.KillDeadThreads;
var
  i: Integer;
begin
  // Check for dead threads
  if csThreadManagment.TryEnter then
  try
    for i := 0 to FThreads.Count - 1 do
      if TProcessorThread(FThreads[i]).IsDead then
      begin
        // Dead thread moverd to other list.
        // New thread created to replace dead one
        TProcessorThread(FThreads[i]).Terminate;
        FThreadsKilling.Add(FThreads[i]);
        try
          FThreads[i] := TProcessorThread.Create(Self);
        except
          on e: Exception do
          begin
            FThreads[i] := nil;
{$IFNDEF NOLOGS}
            WriteLog(
              'TProcessorThread.Create raise: ' + e.ClassName +
              #13#10#9'Message: ' + e.Message,
              9
              );
{$ENDIF}
          end;
        end;
      end;
  finally
    csThreadManagment.Leave
  end;
end; { TThreadsPool.KillDeadThreads }

function TThreadsPool.PoolAverageWaitingTime: Integer;
var
  i: Integer;
begin
  Result := 0;
  if FThreads.Count > 0 then
  begin
    for i := 0 to FThreads.Count - 1 do
      Inc(result, TProcessorThread(FThreads[i]).AverageWaitingTime);
    Result := Result div FThreads.Count
  end
  else
    Result := 1;
end; { TThreadsPool.PoolAverageWaitingTime }

procedure TThreadsPool.WriteLog(const Str: string; Level: Integer = 0);
begin
{$IFNDEF NOLOGS}
  uThreadPool.WriteLog(Str, 0, Level);
{$ENDIF}
end; { TThreadsPool.WriteLog }

// 工作线程仅用于线程池内, 不要直接创建并调用它。
{
******************************* TProcessorThread *******************************
}

constructor TProcessorThread.Create(APool: TThreadsPool);
begin
  WriteLog('创建工作线程', 5);
  inherited Create(True);
  FPool := aPool;

  FAverageWaitingTime := 1000;
  FAverageProcessing := 3000;

  sInitError := '';
  {
  各参数的意义如下:
   
   参数一:填上 nil 即可。
   参数二:是否采用手动调整灯号。
   参数三:灯号的起始状态,False 表示红灯。
   参数四:Event 名称, 对象名称相同的话,会指向同一个对象,所以想要有两个Event对象,便要有两个不同的名称(这名称以字符串来存.为NIL的话系统每次会自己创建一个不同的名字,就是被次创建的都是新的EVENT)。
   传回值:Event handle
  }
  hInitFinished := CreateEvent(nil, True, False, nil);
  hThreadTerminated := CreateEvent(nil, True, False, nil);
  csProcessingDataObject := TCriticalSection.Create;
  try
    WriteLog('TProcessorThread.Create::Resume', 3);
    Resume;
    //阻塞, 等待初始化完成
    WaitForSingleObject(hInitFinished, INFINITE);
    if sInitError <> '' then
      raise Exception.Create(sInitError);
  finally
    CloseHandle(hInitFinished);
  end;
  WriteLog('TProcessorThread.Create::Finished', 3);
end; { TProcessorThread.Create }

destructor TProcessorThread.Destroy;
begin
  WriteLog('工作线程销毁', 5);
  CloseHandle(hThreadTerminated);
  csProcessingDataObject.Free;
  inherited;
end; { TProcessorThread.Destroy }

function TProcessorThread.AverageProcessingTime: DWORD;
begin
  if (FCurState in [tcsProcessing]) then
    Result := NewAverage(FAverageProcessing, GetTickCount - uProcessingStart)
  else
    Result := FAverageProcessing
end; { TProcessorThread.AverageProcessingTime }

function TProcessorThread.AverageWaitingTime: DWORD;
begin
  if (FCurState in [tcsWaiting, tcsCheckingDown]) then
    Result := NewAverage(FAverageWaitingTime, GetTickCount - uWaitingStart)
  else
    Result := FAverageWaitingTime
end; { TProcessorThread.AverageWaitingTime }

procedure TProcessorThread.Execute;

type
  THandleID = (hidTerminateThread, hidRequest, hidCheckPoolDown);
var
  WaitedTime: Integer;
  Handles: array[THandleID] of THandle;

begin
  WriteLog('工作线程进常运行', 3);
  //当前状态:初始化
  FCurState := tcsInitializing;
  try
    //执行外部事件
    FPool.DoThreadInitializing(Self);
  except
    on e: Exception do
      sInitError := e.Message;
  end;

  //初始化完成,初始化Event绿灯
  SetEvent(hInitFinished);

  WriteLog('TProcessorThread.Execute::Initialized', 3);

  //引用线程池的同步 Event
  Handles[hidTerminateThread] := hThreadTerminated;
  Handles[hidRequest] := FPool.hSemRequestCount;
  Handles[hidCheckPoolDown] := FPool.hTimCheckPoolDown;

  //时间戳,
  //todo: 好像在线程中用 GetTickCount; 会不正常
  uWaitingStart := GetTickCount;
  //任务置空
  FProcessingDataObject := nil;

  //大巡环
  while not terminated do
  begin
    //当前状态:等待
    FCurState := tcsWaiting;
    //阻塞线程,使线程休眠
    case WaitForMultipleObjects(Length(Handles), @Handles, False, INFINITE) -
      WAIT_OBJECT_0 of

      WAIT_OBJECT_0 + ord(hidTerminateThread):
        begin
          WriteLog('TProcessorThread.Execute:: Terminate event signaled ', 5);
          //当前状态:正在终止线程
          FCurState := tcsTerminating;
          //退出大巡环(结束线程)
          Break;
        end;

      WAIT_OBJECT_0 + ord(hidRequest):
        begin
          WriteLog('TProcessorThread.Execute:: Request semaphore signaled ', 3);
          //等待的时间
          WaitedTime := GetTickCount - uWaitingStart;
          //重新计算平均等待时间
          FAverageWaitingTime := NewAverage(FAverageWaitingTime, WaitedTime);
          //当前状态:申请任务
          FCurState := tcsGetting;
          //如果等待时间过短,则检查工作线程是否足够
          if WaitedTime < 5 then
            FPool.CheckThreadsForGrow;
          //从线程池的任务队列中得到任务
          FPool.GetRequest(FProcessingDataObject);
          //开始处理的时间戳
          uProcessingStart := GetTickCount;
          //当前状态:执行任务
          FCurState := tcsProcessing;
          try
{$IFNDEF NOLOGS}
            WriteLog('Processing: ' + FProcessingDataObject.TextForLog, 2);
{$ENDIF}
            //执行任务
            FPool.DoProcessRequest(FProcessingDataObject, Self);
          except
            on e: Exception do
              WriteLog(
                'OnProcessRequest for ' + FProcessingDataObject.TextForLog +
                #13#10'raise Exception: ' + e.Message,
                8
                );
          end;

          //释放任务对象
          csProcessingDataObject.Enter;
          try
            FProcessingDataObject.Free;
            FProcessingDataObject := nil;
          finally
            csProcessingDataObject.Leave;
          end;
          //重新计算
          FAverageProcessing := NewAverage(FAverageProcessing, GetTickCount -
            uProcessingStart);
          //当前状态:执行任务完毕
          FCurState := tcsProcessed;
          //执行线程外事件
          FPool.DoProcessed;

          uWaitingStart := GetTickCount;
        end;
      WAIT_OBJECT_0 + ord(hidCheckPoolDown):
        begin
          // !!! Never called under Win9x
          WriteLog('TProcessorThread.Execute:: CheckPoolDown timer signaled ',
            4);
          //当前状态:线程池停机(检查并清除空闲线程和死线程)
          FCurState := tcsCheckingDown;
          FPool.CheckPoolDown;
        end;
    end;
  end;
  FCurState := tcsTerminating;

  FPool.DoThreadFinalizing(Self);
end; { TProcessorThread.Execute }

function TProcessorThread.IamCurrentlyProcess(DataObj: TWorkItem): Boolean;
begin
  csProcessingDataObject.Enter;
  try
    Result := (FProcessingDataObject <> nil) and
      DataObj.IsTheSame(FProcessingDataObject);
  finally
    csProcessingDataObject.Leave;
  end;
end; { TProcessorThread.IamCurrentlyProcess }

function TProcessorThread.InfoText: string;

const
  ThreadStateNames: array[TThreadState] of string =
  (
    'tcsInitializing',
    'tcsWaiting',
    'tcsGetting',
    'tcsProcessing',
    'tcsProcessed',
    'tcsTerminating',
    'tcsCheckingDown'
    );

begin
{$IFNDEF NOLOGS}
  Result := Format(
    '%5d: %15s, AverageWaitingTime=%6d, AverageProcessingTime=%6d',
    [ThreadID, ThreadStateNames[FCurState], AverageWaitingTime,
    AverageProcessingTime]
      );
  case FCurState of
    tcsWaiting:
      Result := Result + ', WaitingTime=' + IntToStr(GetTickCount -
        uWaitingStart);
    tcsProcessing:
      Result := Result + ', ProcessingTime=' + IntToStr(GetTickCount -
        uProcessingStart);
  end;

  csProcessingDataObject.Enter;
  try
    if FProcessingDataObject <> nil then
      Result := Result + ' ' + FProcessingDataObject.TextForLog;
  finally
    csProcessingDataObject.Leave;
  end;
{$ENDIF}
end; { TProcessorThread.InfoText }

function TProcessorThread.IsDead: Boolean;
begin
  Result :=
    Terminated or
    (FPool.ThreadDeadTimeout > 0) and (FCurState = tcsProcessing) and
    (GetTickCount - uProcessingStart > FPool.ThreadDeadTimeout);
  if Result then
    WriteLog('Thread dead', 5);
end; { TProcessorThread.IsDead }

function TProcessorThread.isFinished: Boolean;
begin
  Result := WaitForSingleObject(Handle, 0) = WAIT_OBJECT_0;
end; { TProcessorThread.isFinished }

function TProcessorThread.isIdle: Boolean;
begin
  // 如果线程状态是 tcsWaiting, tcsCheckingDown
  // 并且 空间时间 > 100ms,
  // 并且 平均等候任务时间大于平均工作时间的 50%
  // 则视为空闲。
  Result :=
    (FCurState in [tcsWaiting, tcsCheckingDown]) and
    (AverageWaitingTime > 100) and
    (AverageWaitingTime * 2 > AverageProcessingTime);
end; { TProcessorThread.isIdle }

function TProcessorThread.NewAverage(OldAvg, NewVal: Integer): Integer;
begin
  Result := (OldAvg * 2 + NewVal) div 3;
end; { TProcessorThread.NewAverage }

procedure TProcessorThread.Terminate;
begin
  WriteLog('TProcessorThread.Terminate', 5);
  inherited Terminate;
  SetEvent(hThreadTerminated);
end; { TProcessorThread.Terminate }

procedure TProcessorThread.WriteLog(const Str: string; Level: Integer = 0);
begin
{$IFNDEF NOLOGS}
  uThreadPool.WriteLog(Str, ThreadID, Level);
{$ENDIF}
end; { TProcessorThread.WriteLog }

{
******************************* TCriticalSection *******************************
}

constructor TCriticalSection.Create;
begin
  InitializeCriticalSection(FSection);
end; { TCriticalSection.Create }

destructor TCriticalSection.Destroy;
begin
  DeleteCriticalSection(FSection);
end; { TCriticalSection.Destroy }

procedure TCriticalSection.Enter;
begin
  EnterCriticalSection(FSection);
end; { TCriticalSection.Enter }

procedure TCriticalSection.Leave;
begin
  LeaveCriticalSection(FSection);
end; { TCriticalSection.Leave }

function TCriticalSection.TryEnter: Boolean;
begin
  Result := TryEnterCriticalSection(FSection);
end; { TCriticalSection.TryEnter }

procedure NoLogs(const Str: string; LogID: Integer = 0; Level: Integer = 0);
begin
end;

initialization
  WriteLog := NoLogs;
end.

用法:
// 创建线程池
FThreadPool := TThreadsPool.Create(Self); // 创建线程池
FThreadPool.ThreadsMin := 5; // 初始工作线程数
FThreadPool.ThreadsMax := 50; // 最大允许工作线程数
FThreadPool.OnProcessRequest := DealwithCommRecvData; // 线程工作函数(DealwithCommRecvData在工作者线程的Execute方法中被调用)

// 使用线程池
var
 AWorkItem: TRecvCommDataWorkItem; // 继承自TWorkItem
begin
 AWorkItem := TRecvCommDataWorkItem.Create;
 Move(PData[0], AWorkItem.FRecvData[0], PDataLen);
 AWorkItem.FRecvDataLen := PDataLen;
 FThreadPool.AddRequest(AWorkItem); // 向线程池分配一个任务
end; 

相关评论

阅读本文后您有什么感想? 已有人给出评价!

  • 8 喜欢喜欢
  • 3 顶
  • 1 难过难过
  • 5 囧
  • 3 围观围观
  • 2 无聊无聊

热门评论

最新评论

发表评论 查看所有评论(0)

昵称:
表情: 高兴 可 汗 我不要 害羞 好 下下下 送花 屎 亲亲
字数: 0/500 (您的评论需要经过审核才能显示)
推荐文章

没有数据