根据windows API文档,我们可以使用全局变量将数据从创建线程传递到新线程,我假设相反的情况也可能发生
数据也可以使用全局变量从创建线程传递到新线程。
这是一个数据结构和回调函数,ptr
是指向main
中堆分配内存的指针
typedef struct Output
{
char *ptr;
DWORD len;
}Output, *POutput;
Output out; // global variable
DWORD grab_output(LPVOID args)
{
DWORD dread;
BOOL success = FALSE;
while (1)
{
success = ReadFile(g_hChildStd_OUT_Rd,out.ptr, 1024, &dread, NULL);
if (!success || dread == 0 ) break;
out.ptr = realloc(out.ptr, out.len+1024);
out.len += dread;
}
}
int run()
{
BOOL res;
STARTUPINFO si;
PROCESS_INFORMATION pi;
SECURITY_ATTRIBUTES sa;
DWORD dwThreadIdArray[1];
DWORD n_size;
memset(&si, 0 ,sizeof(si));
memset(&pi, 0, sizeof(pi));
memset(&sa, 0, sizeof(sa));
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.bInheritHandle = TRUE;
sa.lpSecurityDescriptor = NULL;
if (!CreatePipe(&g_hChildStd_OUT_Rd, &g_hChildStd_OUT_Wr, &sa, 0))
return GetLastError();
if (!SetHandleInformation(g_hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0))
return GetLastError();
si.cb = sizeof(STARTUPINFOA);
si.hStdError = g_hChildStd_OUT_Wr;
si.hStdOutput = g_hChildStd_OUT_Wr;
si.dwFlags |= STARTF_USESTDHANDLES;
if(!CreateProcess(NULL,
"C:\Windows\System32\cmd.exe /c dir",
NULL,
NULL,
TRUE,
CREATE_NEW_CONSOLE,
NULL,
NULL,
&si,
&pi
))
{
}
else
{
handle = CreateThread(0, 0, grab_output, NULL, 0, NULL);
}
return 0;
}
int main()
{
out.ptr = malloc(1024);
out.len = 0;
run();
printf("%sn", out.ptr);
}
当运行代码out.ptr
时,返回垃圾值
gcc example.c && ./a.exe
└e╔┐═☺
为了这个问题,假设我将在任何给定的时间运行一个线程
之所以打印垃圾值,是因为您没有明确的理由假设线程在访问全局变量之前完成。
有太多未检查的故障点。现在,检查每个可能出错的函数是否有错误返回,并在这种情况下产生输出,同时在另一个全局变量中设置一个标志。真的,你不应该这么做,但做得多总比做得不够好。然后关闭不使用的进程和线程句柄。
现在我们应该可以讨论同步了。
看起来您想要一次获取所有输出。因此WaitForSingleObject()
在您自己的线程句柄上。要增量生成输出,需要跟踪输入高水位和输出高水位,并使用putc()
仅输出介于两者之间的字符。
也不要忘记null终止您的字符串,否则printf()
将不高兴。
您需要一些方法来在线程和main()
之间传达值已更新的信息。main((很可能会在线程使用ReadFile
之前执行printf
。还有一个竞争条件,ReadFile
可能正在写入缓冲区,而printf
正在读取它
使用互斥、信号量、事件或类似的方法在线程之间进行通信,然后在适当的情况下使用WaitForSingleObject
等。在线程内有一个繁忙的循环或在有线程仍在运行时退出创建者线程main()
也是不可取的。
编辑:
请注意,您还必须从线程中调用return 0
,否则,如果您在缺少return
的情况下,以某种方式从一开始就设法使程序编译,则程序将失控。