c-如何从回调函数将数据写入全局变量



根据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的情况下,以某种方式从一开始就设法使程序编译,则程序将失控。

最新更新