Отслеживание этой многопоточной программы [дубликат]

Редактор потока модифицирует несколько файлов «inplace» при вызове с помощью переключателя -i, который берет файл резервной копии, заканчивающийся как аргумент. Таким образом,

sed -i.bak 's/foo/bar/g' *

заменяет foo на bar во всех файлах в этой папке, но не входит в подпапки. Это, однако, приведет к созданию нового файла .bak для каждого файла в вашем каталоге. Чтобы сделать это рекурсивно для всех файлов в этом каталоге и во всех его подкаталогах, вам понадобится помощник, например find, чтобы пересечь дерево каталогов.

find ./ -print0 | xargs -0 sed -i.bak 's/foo/bar/g' *

find позволяет вам дополнительно ограничивать то, что файлы, которые необходимо изменить, путем указания дополнительных аргументов, таких как find ./ -name '*.php' -or -name '*.html' -print0, если это необходимо.


Примечание: GNU sed не требует окончания файла, sed -i 's/foo/bar/g' * также будет работать; FreeBSD sed требует расширения, но позволяет промежуток между ними, поэтому sed -i .bak s/foo/bar/g * работает.

34
задан Siddharth Billawa 10 October 2015 в 11:54
поделиться

4 ответа

Reentrancy означает, что блокировки получаются по потоку, а не по каждому вызову.

Это вводящее в заблуждение определение. Это правда (вроде), но это не соответствует реальной точке.

Reentrancy означает (в общем, терминологию CS / IT), что вы что-то делаете, и пока вы все еще это делаете, вы делаете это снова. В случае замков это означает, что вы делаете что-то вроде этого в одном потоке :

  1. Приобретайте блокировку на «foo».
  2. Do что-то
  3. Приобретите блокировку на «foo». Обратите внимание, что мы еще не выпустили блокировку, которую мы ранее приобрели.
  4. ...
  5. Блокировать блокировку на «foo»
  6. ...
  7. Блокировка фиксации на «foo»

С помощью механизма блокировки / блокировки реентера попытка получить тот же замок будет успешной и будет увеличивать внутренний счетчик, принадлежащий блокировке. Блокировка будет освобождена только тогда, когда текущий держатель блокировки выпустил его дважды.

Вот пример в Java, использующий примитивные блоки / мониторы объектов ... которые являются реентерабельными:

Object lock = new Object();
...
synchronized (lock) {
    ...
    doSomething(lock, ...)
    ...
}

public void doSomething(Object lock, ...) {
    synchronized (lock) {
        ...
    }
}

Альтернативой реентерабельной является блокировка без повторного входа, где было бы ошибкой для потока попытаться получить блокировку, которую она уже удерживает.

Преимущество использования реентерационных замков заключается в том, что вы надеваете не нужно беспокоиться о возможности сбоя из-за случайного приобретения блокировки, которую вы уже удерживаете. Недостатком является то, что вы не можете предположить, что ничего, что вы вызываете, изменит состояние переменных, которые блокировка предназначена для защиты. Однако это обычно не проблема. Замки обычно используются для защиты от одновременных изменений состояния, сделанных другими потоками .


Так что мне не нужно учитывать взаимоблокировки?

Да, вы это делаете.

Нить не будет зациклена на себя (если блокировка реентерабельной). Тем не менее, вы можете получить тупик, если есть другие потоки, которые могут блокировать объект, который вы пытаетесь заблокировать.

54
ответ дан Stephen C 22 August 2018 в 08:53
поделиться
  • 1
    Поскольку поток запускает процесс, как я могу все еще его делать, то делайте это снова? – znlyj 12 May 2013 в 05:42
  • 2
    См. Пример Java-кода, который я только что добавил. – Stephen C 12 May 2013 в 05:46
  • 3
    Да спасибо. – znlyj 12 May 2013 в 05:51
  • 4
    что вы имеете в виду, говоря: «Вы не можете предположить, что ничего, что вы называете, изменит состояние переменных, которые блокировка предназначена для защиты»? – znlyj 12 May 2013 в 06:29
  • 5
    В основном это означает, что код в первом синхронизированном блоке должен учитывать, что код в методе doSomething может изменять переменные состояния этого класса ... даже если путь вызова, по которому вызван doSomething, запутан и включает в себя другие классы. – Stephen C 12 May 2013 в 06:46

Совместимость Java в книжных состояниях практики - Reentrancy means that locks are acquired on a per-thread rather than per-invocation basis.

Позвольте мне объяснить, что именно это означает. Прежде всего Внутренние замки являются реентерабельными по своей природе. Способ реинтеграции достигается путем поддержания счетчика количества приобретенных замков и владельца замка. Если счетчик равен 0, и владелец не связан с ним, означает, что блокировка не удерживается нитью. Когда поток получает блокировку, JVM записывает владельца и устанавливает счетчик равным 1. Если тот же поток пытается снова получить блокировку, счетчик увеличивается, а при наличии существующего потока синхронизированный счетчик блоков уменьшается. Когда счетчик достигнет 0, блокировка будет высвобождена.

Простым примером будет -

public class Test {
    public synchronized void performTest() {
       //...
    }
}

public class CustomTest extends Test {
    public synchronized void performTest() {
       //...
       super.performTest();
    }
}

без повторного включения в тупик.

9
ответ дан Aniket Thakur 22 August 2018 в 08:53
поделиться
  • 1
    это, вероятно, лучший ответ в потоке – Hussain Akhtar Wahid 'Ghouri' 19 August 2018 в 22:04

Представьте себе что-то вроде этого:

function A():
   lock (X)
       B()
   unlock (X)

function B():
    A()

Теперь мы вызываем A. Происходит следующее:

  • Вводим A, блокируя X
  • Мы входим в B
  • . Мы снова вводим A, снова блокируя X

. Поскольку мы никогда не выходили из первого вызова A, X все еще заблокирован. Это называется повторным входом - пока функция A еще не вернулась, функция A вызывается снова. Если A полагается на какое-то глобальное статическое состояние, это может привести к ошибке «повторного входа», где до того, как статическое состояние будет очищено от выхода функции, функция будет запущена снова, а половина вычисленных значений столкнется с началом второй вызов.

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

В java, lock и synchronized являются повторными входами - если блокировка удерживается нитью, и нить пытается переустановить один и тот же замок, это разрешено. Поэтому, если бы мы написали вышеописанный псевдокод в Java, он бы не зашел в тупик.

15
ответ дан Patashu 22 August 2018 в 08:53
поделиться

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

public void methodA()
{
     // other code
     synchronized(this)
     {
          methodB();
     } 
}

public void methodB()
{
     // other code
     syncrhonized(this)
     {
          // it can still enter this code    
     }

}
1
ответ дан rubixibuc 22 August 2018 в 08:53
поделиться
Другие вопросы по тегам:

Похожие вопросы: