我有一个用C++为Windows编写的程序,这是一个浏览器扩展的本地应用程序.基本上,它通过stdin
从浏览器接收消息,并通过stdout
发回响应.消息是需要使用外部应用程序(如curl
)下载的URL,响应是这些下载的进度/完成.
我的计划流程如下:
1-有一个不断读取stdin
条消息并从浏览器接收消息的主循环
2-主循环为每条消息创建一个std::thread
.向线程提供要下载的URL并启动,然后主循环返回到侦听新消息.
3-在线程中,我使用CreateProcess()
产生一个子进程,比方说curl.exe
,并继续读取它的输出.
4-现在这些线程需要将下载进度发送到浏览器,这是它们通过向程序stdout
写入来完成的.因为多个线程需要同时向它写入数据,所以我有一个用std::lock_guard<std::mutex>
保护的函数,线程使用这个函数写入stdout
.
现在我想把这个程序移植到Linux上,我希望简单地用popen()
取代CreateProcess()
,但我在谷歌上搜索了一下它是否线程安全,尽管我找不到一个明确的答案,但大多数答案都表明它不是.显然,它在引擎盖下使用fork()
和forks and threads don't get along well.
看起来Linux的方法是设置为fork()
,然后使用管道在主程序和分支程序之间进行通信,但这需要我更改程序的整个 struct ,因为它当前是基于线程的.此外,我不知道如何在维护主循环的同时读取来自所有这些Forking 的子进程的管道.我无法想象在不使用线程的情况下这样做,这会让我们回到第一个问题.
所以我想知道有没有其他方法可以做到这一点?
以下是该程序运行方式的simplified个版本:
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);
}