Следующий код содержит потенциальную мертвую блокировку, но, кажется, необходим: для безопасного копирования данных в один контейнер от другого оба контейнера должны быть заблокированы, чтобы препятствовать тому, чтобы изменения произошли в другом потоке.
void foo::copy(const foo & rhs)
{
pMutex->lock();
rhs.pMutex->lock();
// do copy
}
Нечто имеет контейнер STL, и "действительно копируют", по существу состоит из использования станд.:: копия. Как я блокирую оба взаимных исключения, не представляя мертвую блокировку?
Наведите какой-то полный порядок на экземпляры foo
и всегда получайте их блокировки в порядке возрастания или убывания, например. , foo1-> lock ()
, а затем foo2-> lock ()
.
Другой подход - использовать функциональную семантику и вместо этого написать метод foo :: clone
, который создает новый экземпляр, а не уничтожает существующий.
Если ваш код выполняет много блокировок, вам может потребоваться сложный алгоритм предотвращения взаимоблокировок, такой как алгоритм банкира .
Как насчет этого?
void foo::copy(const foo & rhs)
{
scopedLock lock(rhs.pMutex); // release mutex in destructor
foo tmp(rhs);
swap(tmp); // no throw swap locked internally
}
Это исключительная безопасность, а также довольно потокобезопасная. Чтобы сохранить 100% потоки, вам нужно будет просмотреть весь путь кода, а затем еще раз просмотреть его другим взглядом, после чего еще раз просмотреть его ...
Это не очень эффективно, и есть гораздо лучшие способы сделать это в целом (см. ответ @ Anurag), но это просто и хорошо работает для коротких последовательностей:
function stringIntersection(str1, str2) {
var strTemp;
// Swap parameters if necessary to ensure str1 is the shorter
if (str1.length > str2.length) {
strTemp = str1;
str1 = str2;
str2 = strTemp;
}
// Start with the whole of str1 and try shorter substrings until
// we have a common one
var str1Len = str1.length, l = str1Len, start, substring;
while (l > 0) {
start = str1Len - l;
while (start >= 0) {
substring = str1.slice(start, l);
if (str2.indexOf(substring) > -1) {
return substring;
}
start--;
}
l--;
}
return "";
}
var s1 = "Here is a quick guide for the next time you reach"
+ " for your favorite oil and some other topics";
var s2 = "favorite oil and some other topics can be based on"
+ " something blah blah";
alert( stringIntersection(s1, s2) );
-121--4268352- Чтобы избежать взаимоблокировки, следует дождаться блокировки обоих ресурсов:
Не знайте, какой API мьютекса вы используете, так что здесь есть некоторый произвольный псевдокод, предположим, что can _ lock ()
проверяет только, может ли он заблокировать мьютекс, и что try _ lock ()
возвращает true, если он заблокирован, и false, если мьютекс уже заблокирован кем-то другим.
void foo::copy(const foo & rhs)
{
for(;;)
{
if(! pMutex->cany_lock() || ! rhs.pMutex->cany_lock())
{
// Depending on your environment call or dont call sleep()
continue;
}
if(! pMutex->try_lock())
continue;
if(! rhs.pMutex->try_lock())
{
pMutex->try_lock()
continue;
}
break;
}
// do copy
}