QNetworkAccessManager来自线程池

4
一个非常基础的问题。文档提到QNetworkAccessManager中的所有方法都是可重入的。如果是这样,那么在QRunnable中执行get()方法而不使用锁是否合法?我的代码看起来像这样:
class MyClass: public QRunnable
{
    void run()
    {
        ...
        QNetworkAccessManager nam;
        QNetworkReply* reply =  name.get(request)    // No Read-write lock.
        ...
    }
};
2个回答

3

来自Qt文档

[...] 如果一个类的成员函数可以在多个线程中安全地同时调用,只要每个线程使用该类的不同实例,则称该类为可重入

由于您每次都会使用不同的实例(在run()中创建的实例),因此您是安全的。


如果我有一个在不同线程之间共享的QNetworkAccessManager实例,那么从不同的线程调用get方法是否仍然有效?也就是说,如果在QRunnable实例化时将QNetworkAccessManager实例传递给它,并且在run()中调用其get方法,是否仍然能够确保没有问题? - Vishnu Pedireddi
2
@de costa:不行,这会导致程序崩溃。你需要使用QMutex来串行访问它,但是:QNetworkAccessManager是一个QObject,因此需要通过moveToThread()将其移动到线程中以安全地调用它,即使有互斥保护(事件处理程序可能在任何时候调用QObject)。由于QRunnable在无法从外部QThreadPool预测的线程上运行,并且moveToThread()只能将对象推送到另一个线程中,而不能从另一个线程中拉取,因此您不能在未在其中创建QRunnableQObject中使用它们(除非您在内部对它们进行同步,即使它们是线程安全的)。 - Marc Mutz - mmutz
那么,在ThreadPool的每个QRunnable内创建一个QNetworkAccessManager会有多昂贵?这被认为是一种好的做法吗?另一种替代但潜在难以调试的实现是在我的QRunnable中拥有一个QObject并实现信号/槽通信到在创建QTHreadPool的线程上实例化的QNetworkAccessManager。有什么建议吗? - Vishnu Pedireddi
2
@de costo:这是您在原帖中已经在做的事情。关于成本:QNetworkAccessManager基本上是一个可参数化的工厂(如抽象工厂)。如果您不需要可参数性(例如,您不想通过其他支持的协议进行扩展),则在那里创建它应该具有最小的开销。如果由于某种原因无法以此方式使用它,则只需在主线程中使用它,这是稍微更传统的方法。QNetworkReply是QIODevice,并且支持异步操作,例如readyRead()信号,因此您不需要线程(负载受IO绑定限制)。 - Marc Mutz - mmutz
@Marc Mutz:如果我们使用多个QNetworkAccessManager,那么为所有的管理器设置缓存和代理设置就会变得困难。 - philk

0
作为这个问题的一个侧面说明,如果你只是想让GET请求异步执行,QNetworkAccessManager已经是异步的了(文档中有说明)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接