8

linuxのmanページからの「open」の提案に沿ってファイルロックメカニズムを実装しました。これには次のように記載されています。

ロックファイルを使用してアトミックファイルロックを実行し、O_EXCLのNFSサポートへの依存を回避する必要があるポータブルプログラムは、同じファイルシステム上に一意のファイルを作成し(たとえば、ホスト名とPIDを組み込む)、link(2)を使用してロックファイルへのリンクを作成します。link(2)が0を返す場合、ロックは成功しています。それ以外の場合は、一意のファイルでstat(2)を使用して、リンク数が2に増えたかどうかを確認します。この場合、ロックも成功します。

これは完全に機能しているようですが、テストで100%のコードカバレッジを得るには、リンク数が2に増えた場合をカバーする必要があります。

私はグーグルを試しましたが、私が見つけることができるように見えるのは、「それが行われた方法」として逆流した上記の同じ参照です。

リンクが失敗する(-1を返す)状況のセットを誰かが私に説明できますが、リンク数は2に増えますか?

4

2 に答える 2

2

あなたの質問に対する答えは、Linuxプログラマーマニュアルのlink(2)ページの下部にあります。

   On NFS file systems, the return code may  be  wrong  in  case  the  NFS
   server  performs  the link creation and dies before it can say so.  Use
   stat(2) to find out if the link got created.
于 2013-12-18T02:05:44.843 に答える
1

別のファイルを作成するのは何よりも面倒です。代わりにディレクトリを作成し、作成結果を確認してください。Unixのマニュアルには、ディレクトリの作成に成功できるタスクは1つだけであり、ディレクトリがすでに存在する場合は、2つのタスクが同時に試行した場合を含め、もう1つのタスクが失敗することが記載されています。OS自体が問題を処理するので、そうする必要はありません。

古いロックの可能性がなければ、それがあなたがしなければならないすべてです。ただし、事態は発生し、プログラムは中止され、常にロックが解除されるとは限りません。したがって、実装はもう少し複雑になる可能性があります。

スクリプトでは、以下のコードをよく使用しました。古いロックを自動的に処理します。同じことをCで実装できます。マニュアルページを確認してください。

man -s 2 mkdir

EXECUTION_CONTROL_FILE:名前PATHおよびDir名であり、/ usr / tmp/myAppNameのようなものです。

second_of_now:現在の時刻を秒単位で返します(以下に含まれます)

LOCK_MAX_TIME:ロックが古くなったと見なされるまでに存在できる秒数です。

睡眠5:ロックは短くて甘いことをするだろうと常に想定されています。そうでない場合は、おそらくあなたの睡眠サイクルはもっと長くなるはずです。

LockFile() {
  L_DIR=${EXECUTION_CONTROL_FILE}.lock
  L_DIR2=${EXECUTION_CONTROL_FILE}.lock2
  (
  L_STATUS=1
  L_FILE_COUNT=2
  L_COUNT=10
  while [ $L_STATUS != 0 ]; do
    mkdir $L_DIR 2>/dev/null
    L_STATUS=$?
    if [ $L_STATUS = 0 ]; then
      # Create the timetime stamp file
      second_of_now >$L_DIR/timestamp
    else
      # The directory exists, check how long it has been there
      L_NOW=`second_of_now`
      L_THEN=`cat $L_DIR/timestamp 2>/dev/null`
      # The file does not exist, how many times did this happen?
      if [ "$L_THEN" = "" ]; then
        if [ $L_FILE_COUNT != 0 ]; then
          L_THEN=$L_NOW
          L_FILE_COUNT=`expr $L_FILE_COUNT - 1`
        else
          L_THEN=0
        fi
      fi
      if [ `expr $L_NOW - $L_THEN` -gt $LOCK_MAX_TIME ]; then
        # We will try 10 times to unlock, but the 10th time
        # we will force the unlock.
        UnlockFile $L_COUNT
        L_COUNT=`expr $L_COUNT - 1`
      else
        L_COUNT=10  # Reset this back in case it has gone down
        sleep 5
      fi
    fi
  done
  )
  L_STATUS=$?
  return $L_STATUS
}

####
#### Remove access lock
####
UnlockFile() {
  U_DIR=${EXECUTION_CONTROL_FILE}.lock
  U_DIR2=${EXECUTION_CONTROL_FILE}.lock2
  (
  # This 'cd' fixes an issue with UNIX which sometimes report this error:
  #    rm: cannot determine if this is an ancestor of the current working directory
  cd `dirname "${EXECUTION_CONTROL_FILE}"`

  mkdir $U_DIR2 2>/dev/null
  U_STATUS=$?
  if [ $U_STATUS != 0 ]; then
    if [ "$1" != "0" ]; then
      return
    fi
  fi

  trap "rm -rf $U_DIR2" 0

  # The directory exists, check how long it has been there
  # in case it has just been added again
  U_NOW=`second_of_now`
  U_THEN=`cat $U_DIR/timestamp 2>/dev/null`
  # The file does not exist then we assume it is obsolete
  if [ "$U_THEN" = "" ]; then
    U_THEN=0
  fi
  if [ `expr $U_NOW - $U_THEN` -gt $LOCK_MAX_TIME -o "$1" = "mine" ]; then
    # Remove lock directory as it is still too old
    rm -rf $U_DIR
  fi

  # Remove this short lock directory
  rm -rf $U_DIR2
  )
  U_STATUS=$?
  return $U_STATUS
}

####
second_of_now() {
  second_of_day `date "+%y%m%d%H%M%S"`
}

####
#### Return which second of the date/time this is. The parameters must
#### be in the form "yymmddHHMMSS", no centuries for the year and
#### years before 2000 are not supported.
second_of_day() {
  year=`printf "$1\n"|cut -c1-2`
  year=`expr $year + 0`
  month=`printf "$1\n"|cut -c3-4`
  day=`printf "$1\n"|cut -c5-6`
  day=`expr $day - 1`
  hour=`printf "$1\n"|cut -c7-8`
  min=`printf "$1\n"|cut -c9-10`
  sec=`printf "$1\n"|cut -c11-12`
  sec=`expr $min \* 60 + $sec`
  sec=`expr $hour \* 3600 + $sec`
  sec=`expr $day \* 86400 + $sec`
  if [ `expr 20$year % 4` = 0 ]; then
    bisex=29
  else
    bisex=28
  fi
  mm=1
  while [ $mm -lt $month ]; do
    case $mm in
      4|6|9|11) days=30 ;;
      2) days=$bisex ;;
      *) days=31 ;;
    esac
    sec=`expr $days \* 86400 + $sec`
    mm=`expr $mm + 1`
  done
  year=`expr $year + 2000`
  while [ $year -gt 2000 ]; do
    year=`expr $year - 1`
    if [ `expr $year % 4` = 0 ]; then
      sec=`expr 31622400 + $sec`
    else
      sec=`expr 31536000 + $sec`
    fi
  done
  printf "$sec\n"
}

このように使用します:

    # Make sure that 2 operations don't happen at the same time
    LockFile
    # Make sure we get rid of our lock if we exit unexpectedly
    trap "UnlockFile mine" 0
.
.  Do what you have to do
.
    # We need to remove the lock
    UnlockFile mine
于 2013-03-14T17:47:38.743 に答える