TBB spin_mutex внутри parallel_for, чтобы заблокировать критическую секцию
Концептуально, как я могу заблокировать критический раздел внутри tbb::parallel_for
звоните используя tbb:spin_mutex
? Критический раздел составляет менее 20 инструкций, поэтому spin_mutex
идеально. Например, следующий фиктивный код объясняет ситуацию:
function() {
// I'm using lambda functions in parallel_for call here. The parallel_for
// is multithreading across the size of the vector customVec
tbb::parallel_for(
tbb::blocked_range<vector<CustomeType>::iterator>(customVec.begin(), customVec.end(), 1),
[&](tbb::blocked_range<vector<CustomType>::iterator> customVec) {
for (vector<CustomType>::iterator it = customVec.begin(); it != customVec.end(); it++) {
CustomType item = *it;
...
...
// This is the cross-functional call that each thread will call
// critical section is in-side the functionA
item->functionA(param1, param2);
}
...
...
}
);
...
...
}
И функция А:
functionA (Type1 param1, Type2 param2) {
if (conditionX) {
/* This file read is the critical section. So basically, need to
block multiple threads reading the same file to reduce I/O cost
and redundancy. Since file read can be stored in a global variable
that can be accessed in memory by other threads */
fileRead(filename); // Critical line that need to be protected
}
...
...
}
То, с чем я борюсь, это то, как я могу настроить spin_mutex
в functionA()
таким образом mutex
распределяется между потоками, и потоки не переступают друг друга, пытаясь одновременно выполнить критический раздел.
Примечание: предположим, function()
а также functionA()
принадлежит двум отдельным классам C++, и нет никакого наследования на основе классов между двумя классами, которые имеют function()
а также functionA()
как функции-члены
2 ответа
Вы можете рассмотреть возможность использования статического spin_mutex
внутри функции:
functionA (Type1 param1, Type2 param2) {
if (conditionX) {
/* This file read is the critical section. So basically, need to
block multiple threads reading the same file to reduce I/O cost
and redundancy. Since file read can be stored in a global variable
that can be accessed in memory by other threads */
// A static mutex that is shared across all invocations of the function.
static tbb::spin_mutex mtx;
// Acquire a lock
tbb::spin_mutex::scoped_lock lock(mtx);
fileRead(filename); // Critical line that need to be protected
}
...
...
}
Обратите внимание, что он будет работать только с C++11 и более поздними версиями (потому что вам нужна "магическая статика", то есть потокобезопасность инициализации статической переменной).
Я только что нашел решение. Не может быть оптимальным, но решил проблему, которая у меня была. Так что собираюсь опубликовать это как ответ для кого-то, кто может столкнуться с той же проблемой.
В основном решение состоит в том, чтобы определить spin_mutex
объект за пределами parallel_for
и передать его в вызов функции в качестве ссылки. Я разместил тот же пример кода из вопроса с решением ниже:
tbb::spin_mutex mtx; // Declare spin_mutex object
function() {
// I'm using lambda functions in parallel_for call here. The parallel_for
// is multithreading across the size of the vector customVec
tbb::parallel_for(
tbb::blocked_range<vector<CustomeType>::iterator>(customVec.begin(), customVec.end(), 1),
[&](tbb::blocked_range<vector<CustomType>::iterator> customVec) {
for (vector<CustomType>::iterator it = customVec.begin(); it != customVec.end(); it++) {
CustomType item = *it;
...
...
// This is the cross-functional call that each thread will call
// critical section is in-side the functionA
item->functionA(param1, param2, mtx); // pass object as a reference
}
...
...
}
);
...
...
}
и функция А:
// Pass the spin_mutex object by reference
functionA (Type1 param1, Type2 param2, tbb::spin_mutex& mtx) {
if (conditionX) {
/* This file read is the critical section. So basically, need to
block multiple threads reading the same file to reduce I/O cost
and redundancy. Since file read can be stored in a global variable
that can be accessed in memory by other threads */
// Acquire a scope lock
{
tbb::spin_mutex::scoped_lock lock(mtx);
fileRead(filename); // Critical line that need to be protected
}
}
...
...
}