Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/135.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/qt/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 如何在Qt中设计返回值的异步包装器?_C++_Qt_Asynchronous_Design Patterns_Qfuture - Fatal编程技术网

C++ 如何在Qt中设计返回值的异步包装器?

C++ 如何在Qt中设计返回值的异步包装器?,c++,qt,asynchronous,design-patterns,qfuture,C++,Qt,Asynchronous,Design Patterns,Qfuture,我在Qt中为外部可执行文件编写了一个包装器类。 它有很多方法,其中大部分是: 这些都很耗时 需要返回不同类型的值 在这种情况下,同步包装非常简单: class SyncWrapper { public: // Values are fetched *synchronously* in these methods QString name() const; QStringList files() const; bool remove(const QString

我在Qt中为外部可执行文件编写了一个包装器类。 它有很多方法,其中大部分是:

  • 这些都很耗时
  • 需要返回不同类型的值
在这种情况下,同步包装非常简单:

class SyncWrapper {
public:
    // Values are fetched *synchronously* in these methods
    QString name() const;
    QStringList files() const;
    bool remove(const QString &file) const;
};
但是,我想让这个包装器异步,如下所示:

class AsyncWrapper {
    Q_OBJECT
public:
    // Values are fetched *asynchronously* in these methods
    void name() const;
    void files() const;
    void remove(const QString &file) const;
signals:
    // Values are returned via signals
    void nameReady(const QString &name) const;
    void filesReady(const QStringList &files) const;
    void removeDone(bool success) const;
};
问题 我不确定这种模式是否合适,因为我有多个方面:

  • 复制。想象一下有100种方法。每种方法都需要一个专用信号
  • 竞争条件。如果我多次运行同一方法,我无法知道捕获信号的顺序
可能的解决方案 我还提出了一些其他想法:

  • 在调用类方法时,请坚持使用同步包装器并使用
    QtConcurrent::run
    。不幸的是,这是一个非常庞大的解决方案
  • 从方法返回
    QFuture
    对象。同样,这需要在类之外使用
    QFutureWatcher
    s来处理它们,因为类仍然非常庞大
  • 为每个方法创建一个单独的类。如果我没有弄错的话,这是一种命令模式。虽然这将主要增加类的数量,但我相信这是最干净的解决方案

在Qt中设计这种异步包装器的正确方法是什么?

我认为命令模式可以在这里工作

从抽象命令界面开始:

class Command : public QObject
{
    Q_OBJECT
public:
    virtual ~Command() = default;
    virtual void execute() = 0;
signals:
    void done(bool success) const;
};
子类没有那么复杂,只需给它们一些状态并重写
execute
,例如

class NameCommand : public Command
{
    QString _name;
public:
    void execute() override
    {
        _name = ... //fetch name
        emit done(true);
    }
    QString name() const { return _name; }
};

通过这种方式,您可以构建一组执行多个不同操作的对象,但也可以实现命令路由器,并保持异步或非异步运行命令的机会:

class CommandRouter : public QObject
{
    Q_OBJECT
public:
    void run(Command * command, std::function<void(bool)> done, bool async = false)
    {
        connect(command, &Command::done, this, done, (async ? Qt::QueuedConnection : Qt::DirectConnection));
        if(async)
        {
            QtConcurrent::run(command, &Command::execute);
        }
        else
        {
            command->execute();
        }
    }
};
class CommandRouter:公共QObject
{
Q_对象
公众:
无效运行(Command*Command,std::function done,bool async=false)
{
连接(command,&command::done,this,done,(异步?Qt::QueuedConnection:Qt::DirectConnection));
如果(异步)
{
QtConcurrent::run(命令和命令::执行);
}
其他的
{
命令->执行();
}
}
};
所以你会得到这样的结果:

    CommandRouter router;

    RemoveFileCommand removecommand("somefile.tar.gz");
    router.run(&removecommand, [](bool success) {

        qDebug() << "REMOVE " << (success ? "SUCCESSFUL" : "FAILED");

    }, true); //this will run asyncrounously

    NameCommand namecommand;
    router.run(&namecommand, [&namecommand](bool success) {

        if(success)
        {
            qDebug() << "Name: " + namecommand.name();
        }
        else
        {
            qDebug() << "FETCH NAME FAILED";
        }

    }; //this will block
命令路由器;
RemoveFileCommand removecommand(“somefile.tar.gz”);
router.run(&removecommand,[](bool成功){
qDebug()
    CommandRouter router;

    RemoveFileCommand removecommand("somefile.tar.gz");
    router.run(&removecommand, [](bool success) {

        qDebug() << "REMOVE " << (success ? "SUCCESSFUL" : "FAILED");

    }, true); //this will run asyncrounously

    NameCommand namecommand;
    router.run(&namecommand, [&namecommand](bool success) {

        if(success)
        {
            qDebug() << "Name: " + namecommand.name();
        }
        else
        {
            qDebug() << "FETCH NAME FAILED";
        }

    }; //this will block