web-dev-qa-db-ja.com

Linuxの群れ、ファイルを「ちょうど」ロックする方法は?

Bashでは、関数getLockをさまざまなロック名で使用できるようにしています。

function getLock
{
    getLock_FILE="${1}"
    getLock_OP="${2}"
    case "${getLock_OP}" in
        "LOCK_UN")
            flock -u "${getLock_FILE}"
            rm -fr "${getLock_FILE}"
            ;;
        "LOCK_EX")
            flock -x "${getLock_FILE}"
    esac
}

しかし、群れはflock: bad number: myfilelock

Flockでコマンドを実行せずに、ファイルをロックし、必要なときに解放するにはどうすればよいですか?

次のように使用します。

getLock myfilelock LOCK_EX
somecommands
........
getLock myfilelock LOCK_UN
16
JorgeeFG

ファイルをロックするには:

exec 3>filename # open a file handle; this part will always succeed
flock -x 3      # lock the file handle; this part will block

ロックを解除するには:

exec 3>&-       # close the file handle

Flockのmanページで説明されている方法で行うこともできます。

{
  flock -x 3
  ...other stuff here...
} 3>filename

...その場合、ブロックが終了すると、ファイルは自動的に閉じられます。 (ここでは、( )ではなく{ }を使用してサブシェルを使用することもできますが、これは意図的な決定です。サブシェルにはパフォーマンスのペナルティがあり、スコープ変数の変更やその他の状態の変更が行われるためです。 )。


十分に新しいバージョンのbashを実行している場合、ファイル記述子番号を手動で管理する必要はありません。

# this requires a very new bash -- 4.2 or so.
exec {lock_fd}>filename
flock -x "$lock_fd"
exec $lock_fd>&-

...今、あなたの関数には、連想配列と自動FD割り当てが必要です(そして、同じファイルを異なるパスからロックおよびロック解除できるようにするには、GNU readlink)) -したがって、これは古いbashリリースでは機能しません。

declare -A lock_fds=()                        # store FDs in an associative array
getLock() {
  local file=$(readlink -f "$1")              # declare locals; canonicalize name
  local op=$2
  case $op in
    LOCK_UN)
      [[ ${lock_fds[$file]} ]] || return      # if not locked, do nothing
      exec ${lock_fds[$file]}>&-              # close the FD, releasing the lock
      unset lock_fds[$file]                   # ...and clear the map entry.
      ;;
    LOCK_EX)
      [[ ${lock_fds[$file]} ]] && return      # if already locked, do nothing
      local new_lock_fd                       # don't leak this variable
      exec {new_lock_fd}>"$file"              # open the file...
      flock -x "$new_lock_fd"                 # ...lock the fd...
      lock_fds[$file]=$new_lock_fd            # ...and store the locked FD.
      ;;
  esac
}

GNU readlinkが利用できないプラットフォームを使用している場合、readlink -f呼び出しをrealpathから sh-realpath by Michael Kropat (広く利用可能なreadlink機能のみに依存し、GNU拡張機能)には依存しません)。

35
Charles Duffy