Page 1 of 1

自写小工具 多线程执行程序

Posted: 26 Jun 2014, 21:48
by linpinger
功能: 多线程执行程序

缘起: AHK 在并行方面有点吃亏,H版又不怎么会用,于是想到了用C写个多线程执行命令的办法

原理与用法:
  • 设置环境变量FoxTaskCount表示并行任务数
    设置环境变量FoxTask1表示第一个任务要执行的命令,依次类推
    然后运行用C写的程序
    本程序会读取环境变量,开FoxTaskCount个线程执行任务,每个任务获取各自编号的FoxTaskN中的字符串,并用CreateProcess执行,等待执行完毕
    一开始没用CreateProcess,使用的是system命令,这样每个线程都有两个子进程,一个cmd.exe,一个命令进程
linux平台bash类似办法(没测试过)
  • 后台执行for循环中的命令
    wait命令等待所有后台命令执行完毕
windows平台类似办法(貌似不等待)
  • start xxx.bat
    要等待这些批处理执行完毕貌似很蛋疼,网上搜到的方法是VBS或WMI等等,不方便
    bat方法开的进程多了点,每个bat都多一个cmd.exe
AHK 调用例子

Code: Select all

    EnvSet, FoxTaskCount, 2
    EnvSet, FoxTask1, wget -O c:\m1.html "http://www.autohotkey.com"
    EnvSet, FoxTask2, wget -O c:\m2.html "http://www.ahkscript.org"
    runwait, FoxThreads.exe
BAT 调用例子

Code: Select all

set FoxTaskCount=2
set FoxTask1=wget -O c:\m1.html "http://www.autohotkey.com"
set FoxTask2=wget -O c:\m2.html "http://www.ahkscript.org"
FoxThreads.exe
C语言源码(VC6编译)

Code: Select all

#include <stdio.h>
#include <stdlib.h>

#include <windows.h>

// 减小Exe体积
#pragma comment(lib,"msvcrt.lib")
#pragma comment(linker,"/ALIGN:4096" )

// 这个结构是传递给线程的参数
typedef struct {
	int index;
} FoxArg, * pFoxArg;


DWORD _stdcall iamThread(LPVOID lpParameter)
{
	FoxArg tArg = {0};
	int taskindex = 0;

	char * nowenv ;
	char nowEnvName[] = "FoxTask00" ;

	MoveMemory(&tArg, lpParameter, sizeof(tArg));
	taskindex = tArg.index ;

	sprintf(nowEnvName, "FoxTask%i", taskindex);
	nowenv = getenv(nowEnvName) ;

	printf("线程%d开始: %s\n", taskindex, nowenv) ;

	// system(nowenv) ;

	STARTUPINFO si = {sizeof(si)};
	PROCESS_INFORMATION pi;
	CreateProcess(NULL, nowenv, NULL, NULL, false, 0, NULL, NULL, &si, &pi) ;
	WaitForSingleObject(pi.hProcess, INFINITE);

	printf("线程%d结束: %s\n", taskindex, nowenv) ;

	return 0;
}

int main(int argc, char* argv[])
{
	HANDLE h_thread[55] ;
	FoxArg tArg[55] ;

	int taskCount = 0 ; // 任务数
	taskCount = atoi(getenv("FoxTaskCount")) ;
//	printf("任务数=<%d>\n", taskCount) ;
	

	for (int i=0; i<taskCount; i++) {
//		printf("aa:%d\n", i);
		tArg[i].index = i + 1 ;
		h_thread[i] = CreateThread(NULL, 0, iamThread, &(tArg[i]), 0, NULL);
	}

	for (i=0; i<=taskCount; i++) {
		WaitForSingleObject(h_thread[i],INFINITE);  
		CloseHandle(h_thread[i]);  
	}

//	system("pause");
	return 0 ;
}

Re: 自写小工具 多线程执行程序

Posted: 26 Jun 2014, 22:23
by amnesiac
多谢分享。
不懂 C 源码,不过实际是多进程吧?

Re: 自写小工具 多线程执行程序

Posted: 27 Jun 2014, 03:20
by RobertL
感谢分享。
推荐H版,单进程、多线程、线程可控、数据可交互。

Re: 自写小工具 多线程执行程序

Posted: 27 Jun 2014, 04:31
by linpinger
amnesiac wrote:多谢分享。
不懂 C 源码,不过实际是多进程吧?
每个线程运行一个命令,实际表现就是多进程同时运行

Re: 自写小工具 多线程执行程序

Posted: 27 Jun 2014, 04:32
by linpinger
RobertL wrote:感谢分享。
推荐H版,单进程、多线程、线程可控、数据可交互。
H版真心不会用,总感觉很复杂的样子

Re: 自写小工具 多线程执行程序

Posted: 27 Jun 2014, 06:28
by amnesiac
linpinger wrote:
amnesiac wrote:多谢分享。
不懂 C 源码,不过实际是多进程吧?
每个线程运行一个命令,实际表现就是多进程同时运行
绕个圈做同样的事情,直接 AutoHotkey_L 不方便吗?
AHK 在并行方面有点吃亏的说法,你感觉自己需要的是 AutoHotkey_H 那种可交互共享的多线程,不过演示的代码说明实际并没有这种需要。

Re: 自写小工具 多线程执行程序

Posted: 27 Jun 2014, 23:01
by linpinger
amnesiac wrote:
linpinger wrote:
amnesiac wrote:多谢分享。
不懂 C 源码,不过实际是多进程吧?
每个线程运行一个命令,实际表现就是多进程同时运行
绕个圈做同样的事情,直接 AutoHotkey_L 不方便吗?
AHK 在并行方面有点吃亏的说法,你感觉自己需要的是 AutoHotkey_H 那种可交互共享的多线程,不过演示的代码说明实际并没有这种需要。
最新的H版 V1.1.15.0,貌似有个小问题, traytip没有显示气泡

H版的代码,达到相同目的的代码

Code: Select all

AhkDllPath := A_scriptdir . "\AutoHotkeyMini.dll"
t1 := AhkDllThread(AhkDllPath)
t1.ahktextdll("runwait, wget -O c:\1.htm http://www.autohotkey.com")

t2 := AhkDllThread(AhkDllPath)
t2.ahktextdll("runwait, wget -O c:\2.htm http://www.ahkscript.com")

while ( t1.ahkReady() or t2.ahkReady() )
	sleep, 1000
TrayTip, 提示:, 下载完毕

Re: 自写小工具 多线程执行程序

Posted: 02 Jul 2014, 03:17
by RobertL
linpinger wrote: 最新的H版 V1.1.15.0,貌似有个小问题, traytip没有显示气泡
是有这个问题,我去反应过,当时以为是我的问题,你可以再反馈下。

有个TrayTip的替代方案,是一个AHK库,具体我没用过,忘了貌似叫Notify.ahk。
都在H版那帖子里。

Re: 自写小工具 多线程执行程序

Posted: 08 Jul 2014, 22:46
by amnesiac
一开始的 C 代码实现了两个功能:
  1. 开启多个进程执行多个任务;
  2. 判断任务的结束;
在 AutoHotkey_L 可以实现类似的功能,下面的代码未测试:

Code: Select all

#persistent
AllTask =
(
wget -O c:\m1.html "http://www.autohotkey.com"
wget -O c:\m2.html "http://www.ahkscript.org"
)
TaskPIDs := Array()
Loop, Parse, AllTask, `n, %A_Space%%A_Tab%
{
  Run, %A_LoopField%,, Hide, TaskPID
  TaskPIDs.Insert(TaskPID)
}
SetTimer, CheckTask, 500
return

CheckTask:
If (TaskPIDs.MaxIndex = "")
{
  SetTimer, CheckTask, Off
  ToolTip, 所有任务已完成。
}
for Index,Element in TaskPIDs
{
  Process, exist, Element
  if (ErrorLevel = Element)
    return
  TaskPIDs.Remove(Index)
  ToolTip, Task%Index% 已完成。
}
return
只使用进程标识符可能不够可靠,还可以增加其他条件,如进程启动时间。

PS:这个主题考虑移到【脚本函数】。

Re: 自写小工具 多线程执行程序

Posted: 17 Jul 2014, 21:21
by linpinger
作者刚刚修复了这个问题,实测 traytip 终于出字了
RobertL wrote:
linpinger wrote: 最新的H版 V1.1.15.0,貌似有个小问题, traytip没有显示气泡
是有这个问题,我去反应过,当时以为是我的问题,你可以再反馈下。

有个TrayTip的替代方案,是一个AHK库,具体我没用过,忘了貌似叫Notify.ahk。
都在H版那帖子里。