LoginSignup
0
1

More than 3 years have passed since last update.

サブプロセス処理をパイプを使わずに行う

Last updated at Posted at 2019-10-17
パイプとかファイルディスクリプタとか、そーゆー低レイヤーのはなし
boost::processの子プロセスの入力を閉じる https://qiita.com/cielavenir/items/9219162170cf2dd8b144
サブプロセス処理をパイプを使わずに行う https://qiita.com/cielavenir/items/0e69848b705fafec86e1
fstreamのファイルディスクリプタを取得する
ムーブコンストラクタしかないクラスのprotectedメンバを呼び出す
https://qiita.com/cielavenir/items/fe892c564e6b12983776

boost::processをコピーできないならこういう書き方もできると思います。ファイルを削除してもfdは生きるという特性に依存するのでUnix専用になりますが…。

// g++ zstd.cpp -lboost_thread -lboost_system -lboost_filesystem
// zstd < input_file | ./a.out (and compare printed string to original SHA1)

#include <iostream>
#include <fstream>

#include <boost/uuid/sha1.hpp>
#include <boost/algorithm/hex.hpp>

#include <boost/process/system.hpp>
#include <boost/process/io.hpp>
#include <boost/process/pipe.hpp>

#include <boost/iostreams/copy.hpp>
#include <boost/thread.hpp>

#include <boost/filesystem.hpp>
namespace fs = boost::filesystem;

unsigned int byteswap32(unsigned int n){
    const unsigned int m8=0x00ff00ff;
    const unsigned int m16=0x0000ffff;
    n=((n&m8)<<8)|((n>>8)&m8);
    n=((n&m16)<<16)|((n>>16)&m16);
    return n;
}

int _SubprocessFilterPushthread(const std::string &cmd, std::istream &in, std::ostream &out){
    boost::process::opstream enc;
    boost::process::ipstream dec;
    boost::process::child c(cmd, boost::process::std_in < enc, boost::process::std_out > dec);
    auto fpush = [&]{
        /// write to enc ///
        boost::iostreams::copy(in, enc);
        /// flush enc ///
        enc.flush(); // flush is immune to opstream::rdbuf() issue.
        //enc.rdbuf()->sync();
        enc.pipe().close();
    };
    boost::thread(boost::ref(fpush));
    boost::iostreams::copy(dec, out);
    c.wait();
    return c.exit_code();
}

int _SubprocessFilterPopthread(const std::string &cmd, std::istream &in, std::ostream &out){
    boost::process::opstream enc;
    boost::process::ipstream dec;
    boost::process::child c(cmd, boost::process::std_in < enc, boost::process::std_out > dec);
    auto fpop = [&]{
        boost::iostreams::copy(dec, out);
    };
    boost::thread(boost::ref(fpop));
    boost::iostreams::copy(in, enc);
    enc.flush();
    enc.pipe().close();
    c.wait();
    return c.exit_code();
}

int _SubprocessFilterTmpfile(const std::string &cmd, std::istream &in, std::ostream &out, bool inIsFile){
    FILE* ftmpwrite = NULL;
    int fd = _GetFstreamFd(in);
    if(fd<0){
        ftmpwrite = tmpfile();
        fd = fileno(ftmpwrite);
    }
    std::string writename = std::string("/dev/fd/")+std::to_string(fd);
    if(ftmpwrite){
        std::ofstream fw(writename.c_str(),std::ios::out);
        boost::iostreams::copy(in, fw);
        fw.close();
    }
    FILE* ftmpread = tmpfile();
    std::string readname = std::string("/dev/fd/")+std::to_string(fileno(ftmpread));

    int r = system((cmd+(inIsFile?" \"":" < \"")+writename+"\" > \""+readname+"\"").c_str());
    std::ifstream fr(readname.c_str(),std::ios::in);
    boost::iostreams::copy(fr, out);
    fr.close();
    fclose(ftmpread);
    if(ftmpwrite){
        fclose(ftmpwrite);
    }
    return r;
}

int main(){
    std::stringstream ss;
    //_SubprocessFilterPushthread("zstd -d",std::cin,ss);
    //_SubprocessFilterPopthread("zstd -d",std::cin,ss);
    _SubprocessFilterTmpfile("zstd -d",std::cin,ss);

    {
        boost::uuids::detail::sha1 hash;
        unsigned int digest[5];
        hash.process_bytes(ss.str().data(), ss.str().size());
        hash.get_digest((boost::uuids::detail::sha1::digest_type)digest);
        for(int i=0;i<5;i++)digest[i]=byteswap32(digest[i]);
        std::string result;
        boost::algorithm::hex((char*)digest, ((char*)digest) + 20, std::back_inserter(result));
        std::cout << result << std::endl;
    }

    return 0;
}
0
1
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1