我有一个用 C++ 为 Windows 编写的程序,它是浏览器扩展的本机应用程序。基本上它通过
stdin
从浏览器接收消息并通过 stdout
发送回响应。消息是需要用外部应用程序如curl
下载的URL,响应是这些下载的进度/完成情况。
我的程序流程是这样的:
1-有一个主循环不断读取
stdin
并从浏览器接收消息
2-对于每条消息,主循环都会创建一个
std::thread
。该线程被赋予要下载的 URL 并启动,然后主循环返回以监听新消息。
3- 在线程中我生成一个子进程,比如
curl.exe
,使用 CreateProcess()
并继续读取它的输出。
4-现在这些线程需要将下载进度发送到浏览器,他们通过写入程序
stdout
来完成。由于多个线程需要同时写入它,我有一个用std::lock_guard<std::mutex>
保护的函数,线程使用这个函数写入stdout
。
现在我想把这个程序移植到 Linux,我希望简单地用
CreateProcess()
替换 popen()
但我做了一个谷歌搜索关于它是否线程安全甚至我找不到明确的答案,大多数答案表明它不是。显然它在引擎盖下使用fork()
并且叉子和线程不能很好地相处.
看起来 Linux 的方式是
fork()
,然后使用管道在主程序和分支之间进行通信,但这需要我更改程序的整个结构,因为它目前是基于线程的。
所以我想知道是否有另一种方法可以做到这一点?
这是该程序如何工作的简化版本:
std::mutex theMutex;
int main()
{
while(true)
{
char* url = new char[message_length];
fread(url, sizeof(char), message_length, stdin);
std::thread th1(download_thread, url);
th1.detach();
}
return 0;
}
void download_thread(const string url)
{
/* create the process */
CreateProcessW(
"curl.exe",
"curl.exe url",
NULL,
NULL,
TRUE,
processFlags,
NULL,
NULL,
&siStartInfo,
&piProcInfo);
/* keep reading the output of the process until it exits*/
const int BUFSIZE = 1024;
char buf[BUFSIZE];
unsigned long bytesRead = 0;
bSuccess = FALSE;
while(true)
{
bSuccess = ReadFile(h_child_stdout_r, buf, BUFSIZE, &bytesRead, NULL);
if(!bSuccess || bytesRead<=0)
{
break;
}
string output(buf, buf+bytesRead);
write_to_stdout(msg);
}
}
void write_to_stdout(const string msg)
{
std::lock_guard<std::mutex> lock(theMutex);
const unsigned int message_length = msg.length();
fwrite(msg.c_str(), sizeof(char), message_length, stdout);
fflush(stdout);
}