流程管理代码在Linux和Windows上表现不同 - 为什么?

时间:2014-10-29 07:31:48

标签: c++ linux boost process cross-platform

(上下文)我正在开发一个跨平台(Windows和Linux)应用程序,用于根据BitTorrent Sync在计算机之间分发文件。我已经在C#中创建了它,现在正在移植到C ++作为练习。

BTSync可以在API mode中启动,为此,必须启动' btsync '可执行文件将配置文件的名称和位置作为参数传递。

此时,我最大的问题是让我的应用程序处理可执行文件。我在搜索跨平台流程管理库时找到了Boost.Process,并决定尝试一下。似乎v0.5是它的最新工作版本,正如some evidence所暗示的那样,并且很多人都可以使用它。

我按如下方式实现了库(仅限相关代码):

文件: test.hpp

namespace testingBoostProcess
{
    class Test
    {
        void StartSyncing();
    };
}

文件: Test.cpp

#include <string>
#include <vector>
#include <iostream>
#include <boost/process.hpp>
#include <boost/process/mitigate.hpp>
#include "test.hpp"

using namespace std;
using namespace testingBoostProcess;
namespace bpr = ::boost::process;

#ifdef _WIN32
const vector<wstring> EXE_NAME_ARGS = { L"btsync.exe", L"/config", L"conf.json" };
#else
const vector<string> EXE_NAME_ARGS = { "btsync", "--config", "conf.json" };
#endif

void Test::StartSyncing()
{
    cout << "Starting Server...";
    try
    {
        bpr::child exeServer = bpr::execute(bpr::initializers::set_args(EXE_NAME_ARGS),
            bpr::initializers::throw_on_error(), bpr::initializers::inherit_env());

        auto exitStatus = bpr::wait_for_exit(exeServer);    //  type will be either DWORD or int
        int exitCode = BOOST_PROCESS_EXITSTATUS(exitStatus);
        cout << " ok" << "\tstatus: " << exitCode << "\n";
    }
    catch (const exception& excStartExeServer)
    {
        cout << "\n" << "Error: " << excStartExeServer.what() << "\n";
    }
}


(问题)在Windows上,上面的代码将启动 btsync 并等待(阻止),直到进程终止(通过使用任务管理器或API&#39; s shutdown方法),就像所希望的那样 但是在Linux上,它在启动过程后立即完成执行,好像wait_for_exit()根本不存在,尽管 btsync 进程没有终止。

试图查看是否与 btsync 可执行文件本身有关,我用这个简单的程序替换它:

文件: Fake-Btsync.cpp

#include <cstdio>
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#define SLEEP Sleep(20000)
#include <Windows.h>
#else
#include <unistd.h>
#define SLEEP sleep(20)
#endif
using namespace std;

int main(int argc, char* argv[])
{
    for (int i = 0; i < argc; i++)
    {
        printf(argv[i]);
        printf("\n");
    }
    SLEEP;
    return 0;
}


当与此程序一起使用时,我的应用程序可以根据需要运行,而不是从官方网站下载的原始 btsync 。它将阻塞20秒然后退出。

问题:所描述行为的原因是什么?我唯一能想到的是btsync在Linux上重启。但如何确认呢?或者还有什么呢?

更新:我需要做的就是了解forking是什么以及它是如何运作的,正如在回答中所指出的那样(谢谢!)。


问题2:如果我使用系统监视器向子进程发送End命令&#39; Fake-Btsync &#39;当我的主应用程序被阻止时,wait_for_exit()会抛出异常说:

  

waitpid(2)失败:没有子进程

这是一种与Windows不同的行为,它只是简单地说&#34; ok&#34;并以状态0结束。

更新2:这些答案很棒,但并没有以我能够理解的方式完全解决问题2。我将写一个关于该问题的新问题并在此处发布链接。

1 个答案:

答案 0 :(得分:3)

问题是你对btsync的假设。让我们开始吧:

./btsync 
By using this application, you agree to our Privacy Policy, Terms of Use and End User License Agreement.
http://www.bittorrent.com/legal/privacy
http://www.bittorrent.com/legal/terms-of-use
http://www.bittorrent.com/legal/eula

BitTorrent Sync forked to background. pid = 24325. default port = 8888

那么,整个故事就在那里: BitTorrent Sync forked to background 。而已。没什么。如果您愿意,btsync --help会告诉您通过--nodaemon

测试过程终止

让我们使用测试程序--nodaemon运行btsync。在一个单独的子shell中,让我们在5秒后杀死子btsync进程:

sehe@desktop:/tmp$ (./test; echo exit code $?) & (sleep 5; killall btsync)& time wait
[1] 24553
[2] 24554
By using this application, you agree to our Privacy Policy, Terms of Use and End User License Agreement.
http://www.bittorrent.com/legal/privacy
http://www.bittorrent.com/legal/terms-of-use
http://www.bittorrent.com/legal/eula

[20141029 10:51:16.344] total physical memory 536870912 max disk cache 2097152
[20141029 10:51:16.344] Using IP address 192.168.2.136
[20141029 10:51:16.346] Loading config file version 1.4.93
[20141029 10:51:17.389] UPnP: Device error "http://192.168.2.1:49000/l2tpv3.xml": (-2) 
[20141029 10:51:17.407] UPnP: ERROR mapping TCP port 43564 -> 192.168.2.136:43564. Deleting mapping and trying again: (403) Unknown result code (UPnP protocol violation?)
[20141029 10:51:17.415] UPnP: ERROR removing TCP port 43564: (403) Unknown result code (UPnP protocol violation?)
[20141029 10:51:17.423] UPnP: ERROR mapping TCP port 43564 -> 192.168.2.136:43564: (403) Unknown result code (UPnP protocol violation?)
[20141029 10:51:21.428] Received shutdown request via signal 15
[20141029 10:51:21.428] Shutdown. Saving config sync.dat
Starting Server... ok   status: 0
exit code 0
[1]-  Done                    ( ./test; echo exit code $? )
[2]+  Done                    ( sleep 5; killall btsync )

real    0m6.093s
user    0m0.003s
sys 0m0.026s

没问题!

更好的假Btsync

这应该是可移植的,并且在被杀/终止/中断时表现得更好:

#include <boost/asio/signal_set.hpp>
#include <boost/asio.hpp>
#include <iostream>

int main(int argc, char* argv[])
{
    boost::asio::io_service is;
    boost::asio::signal_set ss(is);
    boost::asio::deadline_timer timer(is, boost::posix_time::seconds(20));
    ss.add(SIGINT);
    ss.add(SIGTERM);

    auto stop = [&]{ 
        ss.cancel();    // one of these will be redundant
        timer.cancel();
    };

    ss.async_wait([=](boost::system::error_code ec, int sig){ 
            std::cout << "Signal received: " << sig << " (ec: '" << ec.message() << "')\n"; 
            stop();
        });
    timer.async_wait([&](boost::system::error_code ec){
            std::cout << "Timer: '" << ec.message() << "'\n";
            stop();
        });

    std::copy(argv, argv+argc, std::ostream_iterator<std::string>(std::cout, "\n"));
    is.run();

    return 0;
}

您可以测试它是否表现良好

(./btsync --nodaemon; echo exit code $?) & (sleep 5; killall btsync)& time wait

同样的测试可以用&#34;官方&#34; btsync和&#34;假&#34; btsync。我的linux盒子输出:

sehe@desktop:/tmp$ (./btsync --nodaemon; echo exit code $?) & (sleep 5; killall btsync)& time wait
[1] 24654
[2] 24655
./btsync
--nodaemon
Signal received: 15 (ec: 'Success')
Timer: 'Operation canceled'
exit code 0
[1]-  Done                    ( ./btsync --nodaemon; echo exit code $? )
[2]+  Done                    ( sleep 5; killall btsync )

real    0m5.014s
user    0m0.001s
sys 0m0.014s