2016-12-26 2 views
0

У меня есть функция, которую несколько потоков могут вызывать одновременно. Эта функция имеет входной аргумент. Например, пожалуйста, учитывайте следующие функции:Вызов функции с входными аргументами в многопоточности

bool MyClass::run(QString moduleName) 
{ 
    qDebug() << QThread::currentThreadId(); 
    ... 
} 

У меня есть два варианта использования этой функции. Во-первых, я могу использовать мьютекс в функции выполнения, как показано ниже:

... 
run("Reza"); // can be different for different threads 
... 
bool MyClass::run(QString moduleName) 
{ 
    qDebug() << QThread::currentThreadId(); 
    QMutexLocker locker(&runMutex); 
    ... 
} 

Вторая с помощью мьютекса при вызове этой функции, как показано ниже:

... 
runMutex.lock(); 
run("Reza"); // can be different for different threads 
runMutex.unlock(); 
... 
bool MyClass::run(QString moduleName) 
{ 
    qDebug() << QThread::currentThreadId(); 
    ... 
} 

, который один является правильным и лучше? Изменяется ли входной аргумент (moduleName) в первом параметре? (Я имею в виду при вызове thread pass другой аргумент этой функции)

Заранее благодарим за помощь. Reza

+1

Какой ресурс вы хотите защитить с помощью мьютекса? (и 'qDebug()' не защищен в вашем первом фрагменте). – Jarod42

+0

определить «лучше» ... –

+0

@ Jarod42 У меня есть общий ресурс в моей функции «run», которую я хочу защитить с помощью мьютекса. Я знаю, что qDebug() не защищен. – Reza

ответ

1

Во многих контекстах имеет смысл иметь и! Функция, приобретающая мьютекс внутри себя, использует эту функцию проще и обычно безопаснее использовать. Тем не менее, при явном использовании мьютексов довольно часто бывает необходимо выполнить дополнительные операции в дополнение к тем, которые выполняются методом run(), а также удерживая блокировку. В этом случае у вас будет другая функция, которая приобретает блокировку и которая не может вызвать функцию внутренней блокировки (ну, если мьютекс не является рекурсивным мьютеком, который, на мой взгляд, на самом деле не является хорошей идеей). Выход состоит в том, чтобы иметь версию функции, например, run_locked() или версию с различными параметрами, которая предполагает, что блокировка получена.

При использовании явной блокировки (обычно я стараюсь избегать этого, потому что я не могу рассуждать о коде с помощью блокировок). Мне было полезно иметь соответствующие пары функций, подобные этому (я бы обычно использовал std)

bool MyClass::run(QString moduleName) { 
    QMutexLocker kerberos(&runMutex); 
    return this->run(kerberos, moduleName); 
} 
bool MyClass::run(QMutexLocker& kerberos, QString moduleName) { 
    // do whatever work is needed here 
} 

Передача объекта блокировка охранник убеждается есть приобретенный охранник вокруг, то есть, пользователь не может просто вызвать функцию ожидает блокировку быть приобретена без приобретенного замка охранника. Существует потенциальное неправильное использование, приобретая защитный замок для неправильной блокировки.

+0

@Kuhl Спасибо за ваш быстрый и всеобъемлющий ответ. Как насчет входного аргумента вызывающей функции? У любого потока есть его копия в собственном стеке или она распространена для всех потоков? – Reza

+1

@Reza: вы имеете в виду 'moduleName'? Способ, которым он передается, имеет значение, то есть каждый поток имеет свое значение. Однако я ничего не знаю о 'QString': если это использует общее представление (например, копию в строке записи), могут быть некоторые проблемы. Если вы будете использовать 'std :: string' (и реализацию C++ по крайней мере после C++ 11), представления строк гарантированно не будут разделены, и при доступе к аргументам, переданным по значению, не потребуется блокировки. –

+0

Этот ответ имеет мало смысла без упоминания цели мьютекса и четкого определения ресурса, предположительно защищенного им. Возможно, это потому, что вопрос тоже очень неясен. –

1

Оба метода верны. Но первый из них - лучший метод. Он также дает читаемость кода.

В первом варианте аргументы входного аргумента (Локальная переменная) всегда безопасны. Поскольку каждый поток имеет собственный стек.

1

Dietmar Kühl предоставил хороший ответ для выбора среди упомянутых подходов. Однако я хочу добавить, что минимизация критического раздела всегда является хорошей практикой. Поэтому, если вам не нужно блокировать всю функцию «run()», вы не должны использовать ни один из упомянутых методов, но защитите наименьший возможный критический раздел в «run()».

Смежные вопросы