3

shell 脚本的修改版本将音频文​​件从 FLAC 转换为 MP3 格式。该计算机具有四核 CPU。该脚本使用以下命令运行:

./flac2mp3.sh $(find flac -type f)

这会将flac目录中的 FLAC 文件(文件名中没有空格)转换为目录中的 MP3 文件mp3(与 同级flac)。如果目标 MP3 文件已存在,则脚本会跳过该文件。

问题是有时脚本的两个实例几乎同时检查是否存在同一个 MP3 文件,从而导致 MP3 文件损坏。

您将如何多次运行脚本(即每个内核一次),而不必在每个命令行上指定不同的文件集,并且不覆盖工作?

更新 - 最小竞争条件

该脚本使用以下锁定机制:

  # Convert FLAC to MP3 using tags from flac file.
  #
  if [ ! -e $FLAC.lock ]; then
    touch $FLAC.lock
    flac -dc "$FLAC" | lame${lame_opts} \
      --tt "$TITLE" \
      --tn "$TRACKNUMBER" \
      --tg "$GENRE" \
      --ty "$DATE" \
      --ta "$ARTIST" \
      --tl "$ALBUM" \
      --add-id3v2 \
      - "$MP3"
    rm $FLAC.lock
  fi;

但是,这仍然留下了竞争条件。

4

8 回答 8

6

“lockfile”命令提供了您在没有竞争条件的情况下尝试对 shell 脚本执行的操作。该命令是由 procmail 人员专门为此目的编写的,并且可用于大多数 BSD/Linux 系统(因为 procmail 可用于大多数环境)。

你的测试变成了这样:

lockfile -r 3 $FLAC.lock
if test $? -eq 0 ; then
  flac -dc "$FLAC" | lame${lame_opts} \
    --tt "$TITLE" \
    --tn "$TRACKNUMBER" \
    --tg "$GENRE" \
    --ty "$DATE" \
    --ta "$ARTIST" \
    --tl "$ALBUM" \
    --add-id3v2 \
    - "$MP3"
fi
rm -f $FLAC.lock

或者,您可以让 lockfile 无限期地重试,这样您就不需要测试返回码,而是可以测试输出文件以确定是否运行 flac。

于 2009-09-25T02:57:32.693 回答
4

如果您没有lockfile并且无法安装它(在其任何版本中 - 有几种实现),那么强大且可移植的原子互斥锁是mkdir.

如果您尝试创建的目录已经存在,mkdir则会失败,因此您可以检查一下;创建成功后,您可以保证没有其他合作进程与您的代码同时处于临界区。

if mkdir "$FLAC.lockdir"; then
    # you now have the exclusive lock
    : critical section
    : code goes here
    rmdir "$FLAC.lockdir"
else
    : nothing? to skip this file
    # or maybe sleep 1 and loop back and try again
fi

为了完整起见,也许还要寻找flock您是否在一组可靠地可用的平台上,并且需要一个高性能的替代lockfile.

于 2018-06-27T03:38:19.863 回答
1

您可以实现对其正在处理的 FLAC 文件的锁定。就像是:

if (not flac locked)
  lock flac
  do work
else
  continue to next flac
于 2009-09-24T20:51:38.757 回答
1

将输出发送到具有唯一名称的临时文件,然后将文件重命名为所需的名称。

flac -dc "$FLAC" | lame${lame_opts} \
      --tt "$TITLE" \
      --tn "$TRACKNUMBER" \
      --tg "$GENRE" \
      --ty "$DATE" \
      --ta "$ARTIST" \
      --tl "$ALBUM" \
      --add-id3v2 \
      - "$MP3.$$"
mv "$MP3.$$" "$MP3"

如果竞争条件每隔一段时间就会通过文件锁定系统泄漏,最终输出仍将是一个进程的结果。

于 2009-09-24T22:51:02.510 回答
0

要锁定文件进程,您可以创建一个具有相同名称且扩展名为 .lock 的文件。

在开始编码之前检查 .lock 文件的存在,并可选择确保 lockfile 的日期不是太旧(以防进程终止)。如果不存在,则在编码开始前创建,编码完成后删除。

您也可以对文件进行群聚,但这仅在调用flock() 并写入文件然后关闭和解锁的c 中才真正有效。对于 shell 脚本,您可能正在调用另一个实用程序来编写文件。

于 2009-09-24T21:03:24.123 回答
0

写一个 Makefile 怎么样?

ALL_FLAC=$(wildcard *.flac)
ALL_MP3=$(patsubst %.flac, %.mp3, $(ALL_FLAC)
all: $(ALL_MP3)
%.mp3: %.flac
        $(FLAC) ...

然后做

$ make -j4 all
于 2009-09-24T21:19:03.803 回答
0

在 bash 中,可以设置 noclobber 选项以避免文件覆盖。

帮助设置 | egrep 'noclobber|-C'

于 2009-09-24T21:51:52.223 回答
0

使用FLOM (Free LOCK Manager) 之类的工具并简单地序列化您的命令,如下所示:

flom -- flac ....
于 2014-04-03T20:58:55.347 回答