Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > Использование не static метода из разных поток


Автор: Jawello 20.3.2014, 18:59
Доброе время суток.

Изучал чужой код и наткнулся на следующее:
Создается указатель на объект, объект имеет один метод (назовем его metod), который не работает с внутренними полями класса, только с входящими в метод параметрами (перед ним можно спокойно дописать модификатор static). Этот указатель передается в потоки, и в каждом потоке вызывается указатель на объект->metod(par1, par2). Т.е. каждый из потоков может одновременно обращаться к объекту из кучи и использовать его метод. 
Возник вопрос: не приведет ли к конфликту такой способ вызова? корректно ли вообще так делать?
Если бы метод был статический - я понимаю, что каждый вызов данного метода будет независимый, но как себя будет вести метод в данном случае я не понимаю. 

спасибо. 

Автор: borisbn 21.3.2014, 09:59
Jawello, вызов невиртуального метода класса отличается от вызова обычной функции тем, что в него неявно передаётся первым параметром this. В твоём случае
Код
объект->metod(par1, par2) === metod(объект, par1, par2)

Если метод не использует его (читай не обращается к полям класса), то он, по большому счёту, ничем не отличается от обычной функции. А вот можно ли эту функцию дёргать из разных потоков - вопрос... Не зная, что она делает - трудно сказать. Может файлы открывает... Может к создаёт элементы GUI... 

Автор: Jawello 21.3.2014, 11:26
borisbn, спасибо большое! Я не знал, что this  передается как не явный параметр. Естественно метод не работает с внешними ресурсами, на вход два параметра по ссылке, и все изменения происходят только с ними. Этот трюк явно используется вместе с полиморфизмом, данный метод виртуальный, что позволяет его перегружать в наследуюемых классах, соответственно для каждого класса будет вызван свой метод. Это очень удобно и мне отлично подходит. 
Если бы метод был бы статичным, то пергрузить его скорее всего было бы нельзя (на сколько я знаю статический метод не может быть виртуальным) и пришлось бы использовать какую-то мета информацию для вызова нужного метода нужного класса или явно прописывать это, а это крайне не удобно. 

Еще раз спасибо. 

Автор: Jawello 21.3.2014, 12:21
borisbn, возник еще один вопрос:
У меня класс, в котором есть поле массив указателей - в разных потоках вызывается метод (который был описан выше) и в зависимости от пришедших в него параметров выбирает один из указателей из массива (который поле класса). Метод ни чего не делает с указателями (не модифицирует их ... указатели указывают на похожие объекты, т.е. у них будет вызван метод, который вообще не обращается к полям класса). Так вот, обращение к такому массиву из разных потоков может привести к коллизии? т.е. нужно ли использовать н-р мьютекс? 
По идее операция чтения одного ресурса вполне может происходит из различных потоков и ни к чему плохому это не приведет. Но я не уверен. Буду благодарен за разъяснение. 


Спасибо еще раз)

Автор: borisbn 21.3.2014, 12:43
Jawello, я запутался )))
Приведи (хоть на псевдокоде) минимальный кусок кода, который бы описывал твою ситуацию

Автор: Jawello 21.3.2014, 13:05
Я использую Qt.
Код

class HttpRequestMapperByPath : public HttpRequestHandler
{
    Q_OBJECT
    Q_DISABLE_COPY(HttpRequestMapperByPath)
public:
    HttpRequestMapperByPath(QObject* parent=0);

    ~HttpRequestMapperByPath();

    virtual void service(HttpRequest& request,
                 HttpResponse& response); // данный метод будет вызываться из разных потоков

private:
    static QString prepareServicePath(const QString& n_servicePath);
private:
    QHash<QString, HttpRequestHandler*> m_responseMap;
};

void HttpRequestMapperByPath::service(HttpRequest &request,
                                      HttpResponse &response)
{
    QByteArray path = request.getPath();
    QString pathStr(path);
    qDebug() << "RequestMapper: path=" << pathStr;

    if(!m_responseMap.contains(QString(pathStr)))
    {
        //TODO: добавить отправку сообщения об ошибке
        return;
    }

    HttpRequestHandler* requestHandler = m_responseMap.value(pathStr);

    requestHandler->service(request, response);

    qDebug("RequestMapper: finished request");
}



Как видно из кода: есть базовый класс HttpRequestHandler, у него есть виртуальный метод service. Я его переопределил указанным выше способом. В этом методе я вытаскиваю из QHash указатель на объект класса HttpRequestHandler и в свою очередь вызываю его метод service. Так вот, указатель на объект HttpRequestMapperByPath я передаю в класс, который инициализирует определенное кол-во потоков и в них вызывает метод service класса HttpRequestMapperByPath. Собственно вопрос, не возникнет ли проблем с тем что на все потоки m_responseMap один? ну и не проглядел ли я еще возможные проблемы)

Автор: borisbn 21.3.2014, 13:34
Если к моменту первого вызова HttpRequestMapperByPath::service хэш уже будет заполнен и изменяться больше точно не будет, то Qt гарантирует, что
Цитата
The container classes are implicitly shared, they are reentrant, and they are optimized for speed, low memory consumption, and minimal inline code expansion, resulting in smaller executables. In addition, they are thread-safe in situations where they are used as read-only containers by all threads used to access them.

А вот что делается в requestHandler->service(request, response); - трудно сказать...

Автор: Jawello 21.3.2014, 14:20
Спасибо большое) значит все будет нормально работать как я и предполагал. requestHandler->service(request, response); обязуется работать по тем же принципами, что и service его вызывающий. 

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)