[ 永远的UNIX::UNIX技术资料的宝库 ]

首页 > 编程技术 > 其它 > 正文
UNIX系统的文件信号灯机制
本文出自: 作者: (2001-07-06 19:00:01)

--- 作 为 一 个 多 用 户、 多 任 务 的 操 作 系 统,UNIX 允 许 某 个 程 序 同 时 运 行 多 个 进 程。 但 有 时 又 由 于 系 统 资 源 等 因 素 的 制 约, 要 求 一 次 只 能 有 一 个 进 程 在 运 行。 例 如 在Digital UNIX 下 运 行 第 二 个Netscape 进 程 时, 系 统 报 告 如 下 错 误 信 息:

---- Netscape has detected a /.netscape/lock file.
---- This may indicate that another user is running Netscape using your /.netscape files.

---- 实 际 上, 第 一 个Netscape 进 程 在 运 行 时, 加 了 一 把 锁, 禁 止 其 他Netscape 进 程 启 动。 当 它 结 束 时, 把 锁 打 开, 其 他 进 程 才 能 进 入。 这 就 是UNIX 的 信 号 灯 机 制。

---- 而Netscape 是 用 文 件 作 为 信 号 灯 的。 在 运 行 前, 先 检 查 文 件/.netscape/lock 是 否 存 在: 若 存 在, 表 明 锁 已 挂 上, 新 进 程 不 能 运 行, 只 好 等 待; 若 没 有, 说 明 锁 已 打 开, 可 以 运 行 了。

---- 在 掌 握 了 文 件 信 号 灯 的 机 理 后, 可 以 自 行 设 计 一 套 万 能 加 锁 解 锁 程 序, 为 每 个 程 序 配 上 各 自 的 锁 和 钥 匙。 并 且 使 用 零 字 节 长 度 的 文 件 当 锁, 减 少 系 统 开 销。

---- 我 们 用creat 和unlink 两 个 系 统 调 用 实 现 加 解 锁 和 检 测 操 作。 一 个 进 程 运 行 之 前, 先 通 过unlink 检 测 锁 文 件 是 否 存 在 注1。unlink 系 统 调 用 从 一 个 目 录 中 删 去 一 个 文 件 链, 若 成 功 则 返 回0, 表 示 确 有 文 件 存 在; 若 失 败, 表 明 文 件 不 存 在, 返 回-1。 如 果 还 没 有 上 锁, 就 要 用creat 系 统 调 用 创 建 锁 文 件; 若 锁 已 挂 上, 虽 然 进 程 并 未 运 行, 但 unlink 无 疑 会 删 除 锁 文 件, 所 以 也 要 用creat 来 恢 复。creat 系 统 调 用 创 建 一 个 新 文 件, 函 数 标 题 如 下:


int creat(path, perms) /* create file */
char *path; /* path name */
int perms; /* permission bits */

---- 其 中path 表 示 路 径 加 文 件 名,perms 是10 位 的 文 件 权 限 描 述 字, 在 加 锁 程 序 中 取0。 文 件 在 刚 创 建 时, 初 始 长 度 为 零 字 节, 用 它 来 做 锁 文 件, 可 以 最 大 限 度 地 降 低 系 统 开 销。

---- 锁 文 件 规 定 为: 源 文 件 名+“.lok”。 这 样 一 来, 就 真 正 做 到 了 一 个 程 序 配 一 把 锁。

---- 下 面 就 列 出 加 锁 和 解 锁 的 程 序 清 单。 我 们 用 同 样 的 程 序 完 成 这 两 种 完 全 互 斥 的 操 作, 区 别 在 于 命 令 名 的 不 同。 在C 语 言 源 程 序 里, 变 量argv[0] 表 示 命 令 名,“lockf” 是 上 锁,“unlockf” 是 解 锁。


程序LOCKF.C暨UNLOCKF.C的源代码
#include < stdio.h >
#include < errno.h >
#include < fcntl.h >
#include < cdatyp.h >
void syserr(msg) /*打印系统调用错误信息并中止 */
char *msg;
{
extern int errno, sys_nerr;
extern char *sys_errlist[];

fprintf(stderr, "ERROR: %s (%d", msg, errno);
if (errno >0 && errno< sys_nerr)
fprintf(stderr, "; %s)\n", sys_errlist[errno]);
else
fprintf(stderr, ")\n");
exit(1);
}
short nlock(name) /*上锁过程 */
char *name;
{ char *path, *lockpath();
int fd, tries;
extern int errno;
short unlink_result;

path=lockpath(name); /*制锁 */
unlink_result=unlink(path); /*判断是否已经上锁 */
fd=creat(path, 0); /*上锁 */
if (fd==-1 || close(fd)==-1)
syserr("nlock");
if (unlink_result==-1)
return 0xff;
return (0);
}
void nunlock(name) /*解锁 */
char *name;
{ char *lockpath();
if (unlink(lockpath(name))==-1)
syserr("nunlock");
}
static char *lockpath(name) /*制锁的过程 */
char *name;
{ static char path[20];
char *strcat();

strcpy(path, name);
return(strcat(path, ".lok"));
}
int main(argc, argv)
int argc;
char *argv[];
{ if (argc!=2)
{ printf("Usage: %s filename\n\r", argv[0]);
return(1);
}
if (strcmp(argv[0], "lockf")==0)
if (!nlock(argv[1]))
{ printf("You can not add the same lock twice!\r\n");
return(2);
}
if (strcmp(argv[0], "unlockf")==0)
nunlock(argv[1]);
return(0);
}
本程序的用法是:
lockf 源文件名

unlockf 源文件名

---- 要 真 正 实 现 信 号 灯 机 制, 我 们 还 必 须 准 备 一 个 简 单 的script 文 件signal: if lockf $1 $1 注2 unlockf else echo “Error: Another $1 is running.” fi

---- 这 样 我 们 在 运 行 文 本 编 辑 器dtpad 时, 输 入 下 列 命 令:

---- signal dtpad

---- 反 过 来, 对 于 前 面 提 到 的netscape 程 序, 也 可 以 通 过 编 写 一 个script 文 件supernet 实 现 多 个 进 程 同 时 运 行:


netscape &
rm /.netscape/lock

---- 注1: 还 有 一 种 方 法, 只 适 用 于 普 通 用 户: 在creat 创 建 一 个 新 文 件 时, 即 使 权 限 实 参(permission argument) 不 允 许 写, 该 文 件 也 被 打 开 用 作 写。 但creat 在 截 断 一 个 现 存 文 件 时, 若 无 写 权 限(write permission), 则 失 败。 这 样 就 可 以 只 通 过creat 系 统 调 用 实 现 文 件 信 号 灯 机 制。 但 这 种 做 法 有 一 个 很 明 显 的 缺 点, 就 是 不 适 用 于 超 级 用 户, 因 为 对 于 超 级 用 户 没 有 不 允 许 写 的 东 西。

---- 注2: 这 不 适 于 带& 符 号 的 后 台 进 程。

---- UNIX 系 统 的 文 件 信 号 灯 机 制

---- 作 为 一 个 多 用 户、 多 任 务 的 操 作 系 统,UNIX 允 许 某 个 程 序 同 时 运 行 多 个 进 程。 但 有 时 又 由 于 系 统 资 源 等 因 素 的 制 约, 要 求 一 次 只 能 有 一 个 进 程 在 运 行。 例 如 在Digital UNIX 下 运 行 第 二 个Netscape 进 程 时, 系 统 报 告 如 下 错 误 信 息:

---- Netscape has detected a /.netscape/lock file.

---- This may indicate that another user is running Netscape using your /.netscape files.

---- 实 际 上, 第 一 个Netscape 进 程 在 运 行 时, 加 了 一 把 锁, 禁 止 其 他Netscape 进 程 启 动。 当 它 结 束 时, 把 锁 打 开, 其 他 进 程 才 能 进 入。 这 就 是UNIX 的 信 号 灯 机 制。

---- 而Netscape 是 用 文 件 作 为 信 号 灯 的。 在 运 行 前, 先 检 查 文 件/.netscape/lock 是 否 存 在: 若 存 在, 表 明 锁 已 挂 上, 新 进 程 不 能 运 行, 只 好 等 待; 若 没 有, 说 明 锁 已 打 开, 可 以 运 行 了。

---- 在 掌 握 了 文 件 信 号 灯 的 机 理 后, 可 以 自 行 设 计 一 套 万 能 加 锁 解 锁 程 序, 为 每 个 程 序 配 上 各 自 的 锁 和 钥 匙。 并 且 使 用 零 字 节 长 度 的 文 件 当 锁, 减 少 系 统 开 销。

---- 我 们 用creat 和unlink 两 个 系 统 调 用 实 现 加 解 锁 和 检 测 操 作。 一 个 进 程 运 行 之 前, 先 通 过unlink 检 测 锁 文 件 是 否 存 在 注1。unlink 系 统 调 用 从 一 个 目 录 中 删 去 一 个 文 件 链, 若 成 功 则 返 回0, 表 示 确 有 文 件 存 在; 若 失 败, 表 明 文 件 不 存 在, 返 回-1。 如 果 还 没 有 上 锁, 就 要 用creat 系 统 调 用 创 建 锁 文 件; 若 锁 已 挂 上, 虽 然 进 程 并 未 运 行, 但 unlink 无 疑 会 删 除 锁 文 件, 所 以 也 要 用creat 来 恢 复。creat 系 统 调 用 创 建 一 个 新 文 件, 函 数 标 题 如 下:


int creat(path, perms) /* create file */
char *path; /* path name */
int perms; /* permission bits */

---- 其 中path 表 示 路 径 加 文 件 名,perms 是10 位 的 文 件 权 限 描 述 字, 在 加 锁 程 序 中 取0。 文 件 在 刚 创 建 时, 初 始 长 度 为 零 字 节, 用 它 来 做 锁 文 件, 可 以 最 大 限 度 地 降 低 系 统 开 销。

---- 锁 文 件 规 定 为: 源 文 件 名+“.lok”。 这 样 一 来, 就 真 正 做 到 了 一 个 程 序 配 一 把 锁。

---- 下 面 就 列 出 加 锁 和 解 锁 的 程 序 清 单。 我 们 用 同 样 的 程 序 完 成 这 两 种 完 全 互 斥 的 操 作, 区 别 在 于 命 令 名 的 不 同。 在C 语 言 源 程 序 里, 变 量argv[0] 表 示 命 令 名,“lockf” 是 上 锁,“unlockf” 是 解 锁。

---- 程 序LOCKF.C 暨UNLOCKF.C 的 源 代 码


#include < stdio.h >
#include < errno.h >
#include < fcntl.h >
#include < cdatyp.h >
void syserr(msg) /*打印系统调用错误信息并中止 */
char *msg;
{
extern int errno, sys_nerr;
extern char *sys_errlist[];

fprintf(stderr, "ERROR: %s (%d", msg, errno);
if (errno >0 && errno< sys_nerr)
fprintf(stderr, "; %s)\n", sys_errlist[errno]);
else
fprintf(stderr, ")\n");
exit(1);
}
short nlock(name) /*上锁过程 */
char *name;
{ char *path, *lockpath();
int fd, tries;
extern int errno;
short unlink_result;

path=lockpath(name); /*制锁 */
unlink_result=unlink(path); /*判断是否已经上锁 */
fd=creat(path, 0); /*上锁 */
if (fd==-1 || close(fd)==-1)
syserr("nlock");
if (unlink_result==-1)
return 0xff;
return (0);
}
void nunlock(name) /*解锁 */
char *name;
{ char *lockpath();
if (unlink(lockpath(name))==-1)
syserr("nunlock");
}
static char *lockpath(name) /*制锁的过程 */
char *name;
{ static char path[20];
char *strcat();

strcpy(path, name);
return(strcat(path, ".lok"));
}
int main(argc, argv)
int argc;
char *argv[];
{ if (argc!=2)
{ printf("Usage: %s filename\n\r", argv[0]);
return(1);
}
if (strcmp(argv[0], "lockf")==0)
if (!nlock(argv[1]))
{ printf("You can not add the same lock twice!\r\n");
return(2);
}
if (strcmp(argv[0], "unlockf")==0)
nunlock(argv[1]);
return(0);
}
本程序的用法是:
lockf 源文件名

unlockf 源文件名

---- 要 真 正 实 现 信 号 灯 机 制, 我 们 还 必 须 准 备 一 个 简 单 的script 文 件signal:


if lockf $1
$1 注2
unlockf
else
echo “Error: Another $1 is running.”
fi

---- 这 样 我 们 在 运 行 文 本 编 辑 器dtpad 时, 输 入 下 列 命 令:

---- signal dtpad

---- 反 过 来, 对 于 前 面 提 到 的netscape 程 序, 也 可 以 通 过 编 写 一 个script 文 件supernet 实 现 多 个 进 程 同 时 运 行:


netscape &
rm /.netscape/lock

---- 注1: 还 有 一 种 方 法, 只 适 用 于 普 通 用 户: 在creat 创 建 一 个 新 文 件 时, 即 使 权 限 实 参(permission argument) 不 允 许 写, 该 文 件 也 被 打 开 用 作 写。 但creat 在 截 断 一 个 现 存 文 件 时, 若 无 写 权 限(write permission), 则 失 败。 这 样 就 可 以 只 通 过creat 系 统 调 用 实 现 文 件 信 号 灯 机 制。 但 这 种 做 法 有 一 个 很 明 显 的 缺 点, 就 是 不 适 用 于 超 级 用 户, 因 为 对 于 超 级 用 户 没 有 不 允 许 写 的 东 西。

---- 注2: 这 不 适 于 带& 符 号 的 后 台 进 程。

---- UNIX 系 统 的 文 件 信 号 灯 机 制

---- 作 为 一 个 多 用 户、 多 任 务 的 操 作 系 统,UNIX 允 许 某 个 程 序 同 时 运 行 多 个 进 程。 但 有 时 又 由 于 系 统 资 源 等 因 素 的 制 约, 要 求 一 次 只 能 有 一 个 进 程 在 运 行。 例 如 在Digital UNIX 下 运 行 第 二 个Netscape 进 程 时, 系 统 报 告 如 下 错 误 信 息:

---- Netscape has detected a /.netscape/lock file.

---- This may indicate that another user is running Netscape using your /.netscape files.

---- 实 际 上, 第 一 个Netscape 进 程 在 运 行 时, 加 了 一 把 锁, 禁 止 其 他Netscape 进 程 启 动。 当 它 结 束 时, 把 锁 打 开, 其 他 进 程 才 能 进 入。 这 就 是UNIX 的 信 号 灯 机 制。

---- 而Netscape 是 用 文 件 作 为 信 号 灯 的。 在 运 行 前, 先 检 查 文 件/.netscape/lock 是 否 存 在: 若 存 在, 表 明 锁 已 挂 上, 新 进 程 不 能 运 行, 只 好 等 待; 若 没 有, 说 明 锁 已 打 开, 可 以 运 行 了。

---- 在 掌 握 了 文 件 信 号 灯 的 机 理 后, 可 以 自 行 设 计 一 套 万 能 加 锁 解 锁 程 序, 为 每 个 程 序 配 上 各 自 的 锁 和 钥 匙。 并 且 使 用 零 字 节 长 度 的 文 件 当 锁, 减 少 系 统 开 销。

---- 我 们 用creat 和unlink 两 个 系 统 调 用 实 现 加 解 锁 和 检 测 操 作。 一 个 进 程 运 行 之 前, 先 通 过unlink 检 测 锁 文 件 是 否 存 在 注1。unlink 系 统 调 用 从 一 个 目 录 中 删 去 一 个 文 件 链, 若 成 功 则 返 回0, 表 示 确 有 文 件 存 在; 若 失 败, 表 明 文 件 不 存 在, 返 回-1。 如 果 还 没 有 上 锁, 就 要 用creat 系 统 调 用 创 建 锁 文 件; 若 锁 已 挂 上, 虽 然 进 程 并 未 运 行, 但 unlink 无 疑 会 删 除 锁 文 件, 所 以 也 要 用creat 来 恢 复。creat 系 统 调 用 创 建 一 个 新 文 件, 函 数 标 题 如 下:


int creat(path, perms) /* create file */
char *path; /* path name */
int perms; /* permission bits */

---- 其 中path 表 示 路 径 加 文 件 名,perms 是10 位 的 文 件 权 限 描 述 字, 在 加 锁 程 序 中 取0。 文 件 在 刚 创 建 时, 初 始 长 度 为 零 字 节, 用 它 来 做 锁 文 件, 可 以 最 大 限 度 地 降 低 系 统 开 销。

---- 锁 文 件 规 定 为: 源 文 件 名+“.lok”。 这 样 一 来, 就 真 正 做 到 了 一 个 程 序 配 一 把 锁。

---- 下 面 就 列 出 加 锁 和 解 锁 的 程 序 清 单。 我 们 用 同 样 的 程 序 完 成 这 两 种 完 全 互 斥 的 操 作, 区 别 在 于 命 令 名 的 不 同。 在C 语 言 源 程 序 里, 变 量argv[0] 表 示 命 令 名,“lockf” 是 上 锁,“unlockf” 是 解 锁。

---- 程 序LOCKF.C 暨UNLOCKF.C 的 源 代 码


#include < stdio.h >
#include < errno.h >
#include < fcntl.h >
#include < cdatyp.h >
void syserr(msg) /*打印系统调用错误信息并中止 */
char *msg;
{
extern int errno, sys_nerr;
extern char *sys_errlist[];

fprintf(stderr, "ERROR: %s (%d", msg, errno);
if (errno >0 && errno< sys_nerr)
fprintf(stderr, "; %s)\n", sys_errlist[errno]);
else
fprintf(stderr, ")\n");
exit(1);
}
short nlock(name) /*上锁过程 */
char *name;
{ char *path, *lockpath();
int fd, tries;
extern int errno;
short unlink_result;

path=lockpath(name); /*制锁 */
unlink_result=unlink(path); /*判断是否已经上锁 */
fd=creat(path, 0); /*上锁 */
if (fd==-1 || close(fd)==-1)
syserr("nlock");
if (unlink_result==-1)
return 0xff;
return (0);
}
void nunlock(name) /*解锁 */
char *name;
{ char *lockpath();
if (unlink(lockpath(name))==-1)
syserr("nunlock");
}
static char *lockpath(name) /*制锁的过程 */
char *name;
{ static char path[20];
char *strcat();

strcpy(path, name);
return(strcat(path, ".lok"));
}
int main(argc, argv)
int argc;
char *argv[];
{ if (argc!=2)
{ printf("Usage: %s filename\n\r", argv[0]);
return(1);
}
if (strcmp(argv[0], "lockf")==0)
if (!nlock(argv[1]))
{ printf("You can not add the same lock twice!\r\n");
return(2);
}
if (strcmp(argv[0], "unlockf")==0)
nunlock(argv[1]);
return(0);
}
本程序的用法是:
lockf 源文件名

unlockf 源文件名

---- 要 真 正 实 现 信 号 灯 机 制, 我 们 还 必 须 准 备 一 个 简 单 的script 文 件signal:


if lockf $1
$1 注2
unlockf
else
echo “Error: Another $1 is running.”
fi

---- 这 样 我 们 在 运 行 文 本 编 辑 器dtpad 时, 输 入 下 列 命 令:

---- signal dtpad

---- 反 过 来, 对 于 前 面 提 到 的netscape 程 序, 也 可 以 通 过 编 写 一 个script 文 件supernet 实 现 多 个 进 程 同 时 运 行:


netscape &
rm /.netscape/lock

---- 注1: 还 有 一 种 方 法, 只 适 用 于 普 通 用 户: 在creat 创 建 一 个 新 文 件 时, 即 使 权 限 实 参(permission argument) 不 允 许 写, 该 文 件 也 被 打 开 用 作 写。 但creat 在 截 断 一 个 现 存 文 件 时, 若 无 写 权 限(write permission), 则 失 败。 这 样 就 可 以 只 通 过creat 系 统 调 用 实 现 文 件 信 号 灯 机 制。 但 这 种 做 法 有 一 个 很 明 显 的 缺 点, 就 是 不 适 用 于 超 级 用 户, 因 为 对 于 超 级 用 户 没 有 不 允 许 写 的 东 西。

---- 注2: 这 不 适 于 带& 符 号 的 后 台 进 程。

---- UNIX 系 统 的 文 件 信 号 灯 机 制

---- 作 为 一 个 多 用 户、 多 任 务 的 操 作 系 统,UNIX 允 许 某 个 程 序 同 时 运 行 多 个 进 程。 但 有 时 又 由 于 系 统 资 源 等 因 素 的 制 约, 要 求 一 次 只 能 有 一 个 进 程 在 运 行。 例 如 在Digital UNIX 下 运 行 第 二 个Netscape 进 程 时, 系 统 报 告 如 下 错 误 信 息:

---- Netscape has detected a /.netscape/lock file.

---- This may indicate that another user is running Netscape using your /.netscape files.

---- 实 际 上, 第 一 个Netscape 进 程 在 运 行 时, 加 了 一 把 锁, 禁 止 其 他Netscape 进 程 启 动。 当 它 结 束 时, 把 锁 打 开, 其 他 进 程 才 能 进 入。 这 就 是UNIX 的 信 号 灯 机 制。

---- 而Netscape 是 用 文 件 作 为 信 号 灯 的。 在 运 行 前, 先 检 查 文 件/.netscape/lock 是 否 存 在: 若 存 在, 表 明 锁 已 挂 上, 新 进 程 不 能 运 行, 只 好 等 待; 若 没 有, 说 明 锁 已 打 开, 可 以 运 行 了。

---- 在 掌 握 了 文 件 信 号 灯 的 机 理 后, 可 以 自 行 设 计 一 套 万 能 加 锁 解 锁 程 序, 为 每 个 程 序 配 上 各 自 的 锁 和 钥 匙。 并 且 使 用 零 字 节 长 度 的 文 件 当 锁, 减 少 系 统 开 销。

---- 我 们 用creat 和unlink 两 个 系 统 调 用 实 现 加 解 锁 和 检 测 操 作。 一 个 进 程 运 行 之 前, 先 通 过unlink 检 测 锁 文 件 是 否 存 在 注1。unlink 系 统 调 用 从 一 个 目 录 中 删 去 一 个 文 件 链, 若 成 功 则 返 回0, 表 示 确 有 文 件 存 在; 若 失 败, 表 明 文 件 不 存 在, 返 回-1。 如 果 还 没 有 上 锁, 就 要 用creat 系 统 调 用 创 建 锁 文 件; 若 锁 已 挂 上, 虽 然 进 程 并 未 运 行, 但 unlink 无 疑 会 删 除 锁 文 件, 所 以 也 要 用creat 来 恢 复。creat 系 统 调 用 创 建 一 个 新 文 件, 函 数 标 题 如 下:


int creat(path, perms) /* create file */
char *path; /* path name */
int perms; /* permission bits */

---- 其 中path 表 示 路 径 加 文 件 名,perms 是10 位 的 文 件 权 限 描 述 字, 在 加 锁 程 序 中 取0。 文 件 在 刚 创 建 时, 初 始 长 度 为 零 字 节, 用 它 来 做 锁 文 件, 可 以 最 大 限 度 地 降 低 系 统 开 销。
---- 锁 文 件 规 定 为: 源 文 件 名+“.lok”。 这 样 一 来, 就 真 正 做 到 了 一 个 程 序 配 一 把 锁。

---- 下 面 就 列 出 加 锁 和 解 锁 的 程 序 清 单。 我 们 用 同 样 的 程 序 完 成 这 两 种 完 全 互 斥 的 操 作, 区 别 在 于 命 令 名 的 不 同。 在C 语 言 源 程 序 里, 变 量argv[0] 表 示 命 令 名,“lockf” 是 上 锁,“unlockf” 是 解 锁。

---- 程 序LOCKF.C 暨UNLOCKF.C 的 源 代 码 #include < stdio.h > #include < errno.h > #include < fcntl.h > #include < cdatyp.h > void syserr(msg) /*打印系统调用错误信息并中止 */ char *msg; { extern int errno, sys_nerr; extern char *sys_errlist[]; fprintf(stderr, "ERROR: %s (%d", msg, errno); if (errno >0 && errno< sys_nerr) fprintf(stderr, "; %s)\n", sys_errlist[errno]); else fprintf(stderr, ")\n"); exit(1); } short nlock(name) /*上锁过程 */ char *name; { char *path, *lockpath(); int fd, tries; extern int errno; short unlink_result; path=lockpath(name); /*制锁 */ unlink_result=unlink(path); /*判断是否已经上锁 */ fd=creat(path, 0); /*上锁 */ if (fd==-1 || close(fd)==-1) syserr("nlock"); if (unlink_result==-1) return 0xff; return (0); } void nunlock(name) /*解锁 */ char *name; { char *lockpath(); if (unlink(lockpath(name))==-1) syserr("nunlock"); } static char *lockpath(name) /*制锁的过程 */ char *name; { static char path[20]; char *strcat(); strcpy(path, name); return(strcat(path, ".lok")); } int main(argc, argv) int argc; char *argv[]; { if (argc!=2) { printf("Usage: %s filename\n\r", argv[0]); return(1); } if (strcmp(argv[0], "lockf")==0) if (!nlock(argv[1])) { printf("You can not add the same lock twice!\r\n"); return(2); } if (strcmp(argv[0], "unlockf")==0) nunlock(argv[1]); return(0); } 本程序的用法是: lockf 源文件名 或 unlockf 源文件名

---- 要 真 正 实 现 信 号 灯 机 制, 我 们 还 必 须 准 备 一 个 简 单 的script 文 件signal:


if lockf $1
$1 注2
unlockf
else
echo “Error: Another $1 is running.”
fi

---- 这 样 我 们 在 运 行 文 本 编 辑 器dtpad 时, 输 入 下 列 命 令:

---- signal dtpad

---- 反 过 来, 对 于 前 面 提 到 的netscape 程 序, 也 可 以 通 过 编 写 一 个script 文 件supernet 实 现 多 个 进 程 同 时 运 行:


netscape &
rm /.netscape/lock

---- 注1: 还 有 一 种 方 法, 只 适 用 于 普 通 用 户: 在creat 创 建 一 个 新 文 件 时, 即 使 权 限 实 参(permission argument) 不 允 许 写, 该 文 件 也 被 打 开 用 作 写。 但creat 在 截 断 一 个 现 存 文 件 时, 若 无 写 权 限(write permission), 则 失 败。 这 样 就 可 以 只 通 过creat 系 统 调 用 实 现 文 件 信 号 灯 机 制。 但 这 种 做 法 有 一 个 很 明 显 的 缺 点, 就 是 不 适 用 于 超 级 用 户, 因 为 对 于 超 级 用 户 没 有 不 允 许 写 的 东 西。

---- 注2: 这 不 适 于 带& 符 号 的 后 台 进 程。

---- UNIX 系 统 的 文 件 信 号 灯 机 制

---- 作 为 一 个 多 用 户、 多 任 务 的 操 作 系 统,UNIX 允 许 某 个 程 序 同 时 运 行 多 个 进 程。 但 有 时 又 由 于 系 统 资 源 等 因 素 的 制 约, 要 求 一 次 只 能 有 一 个 进 程 在 运 行。 例 如 在Digital UNIX 下 运 行 第 二 个Netscape 进 程 时, 系 统 报 告 如 下 错 误 信 息:

---- Netscape has detected a /.netscape/lock file.

---- This may indicate that another user is running Netscape using your /.netscape files.

---- 实 际 上, 第 一 个Netscape 进 程 在 运 行 时, 加 了 一 把 锁, 禁 止 其 他Netscape 进 程 启 动。 当 它 结 束 时, 把 锁 打 开, 其 他 进 程 才 能 进 入。 这 就 是UNIX 的 信 号 灯 机 制。

---- 而Netscape 是 用 文 件 作 为 信 号 灯 的。 在 运 行 前, 先 检 查 文 件/.netscape/lock 是 否 存 在: 若 存 在, 表 明 锁 已 挂 上, 新 进 程 不 能 运 行, 只 好 等 待; 若 没 有, 说 明 锁 已 打 开, 可 以 运 行 了。

---- 在 掌 握 了 文 件 信 号 灯 的 机 理 后, 可 以 自 行 设 计 一 套 万 能 加 锁 解 锁 程 序, 为 每 个 程 序 配 上 各 自 的 锁 和 钥 匙。 并 且 使 用 零 字 节 长 度 的 文 件 当 锁, 减 少 系 统 开 销。

---- 我 们 用creat 和unlink 两 个 系 统 调 用 实 现 加 解 锁 和 检 测 操 作。 一 个 进 程 运 行 之 前, 先 通 过unlink 检 测 锁 文 件 是 否 存 在 注1。unlink 系 统 调 用 从 一 个 目 录 中 删 去 一 个 文 件 链, 若 成 功 则 返 回0, 表 示 确 有 文 件 存 在; 若 失 败, 表 明 文 件 不 存 在, 返 回-1。 如 果 还 没 有 上 锁, 就 要 用creat 系 统 调 用 创 建 锁 文 件; 若 锁 已 挂 上, 虽 然 进 程 并 未 运 行, 但 unlink 无 疑 会 删 除 锁 文 件, 所 以 也 要 用creat 来 恢 复。creat 系 统 调 用 创 建 一 个 新 文 件, 函 数 标 题 如 下:


int creat(path, perms) /* create file */
char *path; /* path name */
int perms; /* permission bits */

---- 其 中path 表 示 路 径 加 文 件 名,perms 是10 位 的 文 件 权 限 描 述 字, 在 加 锁 程 序 中 取0。 文 件 在 刚 创 建 时, 初 始 长 度 为 零 字 节, 用 它 来 做 锁 文 件, 可 以 最 大 限 度 地 降 低 系 统 开 销。

---- 锁 文 件 规 定 为: 源 文 件 名+“.lok”。 这 样 一 来, 就 真 正 做 到 了 一 个 程 序 配 一 把 锁。

---- 下 面 就 列 出 加 锁 和 解 锁 的 程 序 清 单。 我 们 用 同 样 的 程 序 完 成 这 两 种 完 全 互 斥 的 操 作, 区 别 在 于 命 令 名 的 不 同。 在C 语 言 源 程 序 里, 变 量argv[0] 表 示 命 令 名,“lockf” 是 上 锁,“unlockf” 是 解 锁。

---- 程 序LOCKF.C 暨UNLOCKF.C 的 源 代 码


#include < stdio.h >
#include < errno.h >
#include < fcntl.h >
#include < cdatyp.h >
void syserr(msg) /*打印系统调用错误信息并中止 */
char *msg;
{
extern int errno, sys_nerr;
extern char *sys_errlist[];

fprintf(stderr, "ERROR: %s (%d", msg, errno);
if (errno >0 && errno< sys_nerr)
fprintf(stderr, "; %s)\n", sys_errlist[errno]);
else
fprintf(stderr, ")\n");
exit(1);
}
short nlock(name) /*上锁过程 */
char *name;
{ char *path, *lockpath();
int fd, tries;
extern int errno;
short unlink_result;

path=lockpath(name); /*制锁 */
unlink_result=unlink(path); /*判断是否已经上锁 */
fd=creat(path, 0); /*上锁 */
if (fd==-1 || close(fd)==-1)
syserr("nlock");
if (unlink_result==-1)
return 0xff;
return (0);
}
void nunlock(name) /*解锁 */
char *name;
{ char *lockpath();
if (unlink(lockpath(name))==-1)
syserr("nunlock");
}
static char *lockpath(name) /*制锁的过程 */
char *name;
{ static char path[20];
char *strcat();

strcpy(path, name);
return(strcat(path, ".lok"));
}
int main(argc, argv)
int argc;
char *argv[];
{ if (argc!=2)
{ printf("Usage: %s filename\n\r", argv[0]);
return(1);
}
if (strcmp(argv[0], "lockf")==0)
if (!nlock(argv[1]))
{ printf("You can not add the same lock twice!\r\n");
return(2);
}
if (strcmp(argv[0], "unlockf")==0)
nunlock(argv[1]);
return(0);
}
本程序的用法是:
lockf 源文件名

unlockf 源文件名

---- 要 真 正 实 现 信 号 灯 机 制, 我 们 还 必 须 准 备 一 个 简 单 的script 文 件signal: if lockf $1 $1 注2 unlockf else echo “Error: Another $1 is running.” fi

---- 这 样 我 们 在 运 行 文 本 编 辑 器dtpad 时, 输 入 下 列 命 令:

---- signal dtpad

---- 反 过 来, 对 于 前 面 提 到 的netscape 程 序, 也 可 以 通 过 编 写 一 个script 文 件supernet 实 现 多 个 进 程 同 时 运 行:


netscape &
rm /.netscape/lock

---- 注1: 还 有 一 种 方 法, 只 适 用 于 普 通 用 户: 在creat 创 建 一 个 新 文 件 时, 即 使 权 限 实 参(permission argument) 不 允 许 写, 该 文 件 也 被 打 开 用 作 写。 但creat 在 截 断 一 个 现 存 文 件 时, 若 无 写 权 限(write permission), 则 失 败。 这 样 就 可 以 只 通 过creat 系 统 调 用 实 现 文 件 信 号 灯 机 制。 但 这 种 做 法 有 一 个 很 明 显 的 缺 点, 就 是 不 适 用 于 超 级 用 户, 因 为 对 于 超 级 用 户 没 有 不 允 许 写 的 东 西。

---- 注2: 这 不 适 于 带& 符 号 的 后 台 进 程。

---- UNIX 系 统 的 文 件 信 号 灯 机 制

---- 作 为 一 个 多 用 户、 多 任 务 的 操 作 系 统,UNIX 允 许 某 个 程 序 同 时 运 行 多 个 进 程。 但 有 时 又 由 于 系 统 资 源 等 因 素 的 制 约, 要 求 一 次 只 能 有 一 个 进 程 在 运 行。 例 如 在Digital UNIX 下 运 行 第 二 个Netscape 进 程 时, 系 统 报 告 如 下 错 误 信 息:

---- Netscape has detected a /.netscape/lock file.

---- This may indicate that another user is running Netscape using your /.netscape files.

---- 实 际 上, 第 一 个Netscape 进 程 在 运 行 时, 加 了 一 把 锁, 禁 止 其 他Netscape 进 程 启 动。 当 它 结 束 时, 把 锁 打 开, 其 他 进 程 才 能 进 入。 这 就 是UNIX 的 信 号 灯 机 制。

---- 而Netscape 是 用 文 件 作 为 信 号 灯 的。 在 运 行 前, 先 检 查 文 件/.netscape/lock 是 否 存 在: 若 存 在, 表 明 锁 已 挂 上, 新 进 程 不 能 运 行, 只 好 等 待; 若 没 有, 说 明 锁 已 打 开, 可 以 运 行 了。

---- 在 掌 握 了 文 件 信 号 灯 的 机 理 后, 可 以 自 行 设 计 一 套 万 能 加 锁 解 锁 程 序, 为 每 个 程 序 配 上 各 自 的 锁 和 钥 匙。 并 且 使 用 零 字 节 长 度 的 文 件 当 锁, 减 少 系 统 开 销。

---- 我 们 用creat 和unlink 两 个 系 统 调 用 实 现 加 解 锁 和 检 测 操 作。 一 个 进 程 运 行 之 前, 先 通 过unlink 检 测 锁 文 件 是 否 存 在 注1。unlink 系 统 调 用 从 一 个 目 录 中 删 去 一 个 文 件 链, 若 成 功 则 返 回0, 表 示 确 有 文 件 存 在; 若 失 败, 表 明 文 件 不 存 在, 返 回-1。 如 果 还 没 有 上 锁, 就 要 用creat 系 统 调 用 创 建 锁 文 件; 若 锁 已 挂 上, 虽 然 进 程 并 未 运 行, 但 unlink 无 疑 会 删 除 锁 文 件, 所 以 也 要 用creat 来 恢 复。creat 系 统 调 用 创 建 一 个 新 文 件, 函 数 标 题 如 下:


int creat(path, perms) /* create file */
char *path; /* path name */
int perms; /* permission bits */

---- 其 中path 表 示 路 径 加 文 件 名,perms 是10 位 的 文 件 权 限 描 述 字, 在 加 锁 程 序 中 取0。 文 件 在 刚 创 建 时, 初 始 长 度 为 零 字 节, 用 它 来 做 锁 文 件, 可 以 最 大 限 度 地 降 低 系 统 开 销。

---- 锁 文 件 规 定 为: 源 文 件 名+“.lok”。 这 样 一 来, 就 真 正 做 到 了 一 个 程 序 配 一 把 锁。

---- 下 面 就 列 出 加 锁 和 解 锁 的 程 序 清 单。 我 们 用 同 样 的 程 序 完 成 这 两 种 完 全 互 斥 的 操 作, 区 别 在 于 命 令 名 的 不 同。 在C 语 言 源 程 序 里, 变 量argv[0] 表 示 命 令 名,“lockf” 是 上 锁,“unlockf” 是 解 锁。

---- 程 序LOCKF.C 暨UNLOCKF.C 的 源 代 码


#include < stdio.h >
#include < errno.h >
#include < fcntl.h >
#include < cdatyp.h >
void syserr(msg) /*打印系统调用错误信息并中止 */
char *msg;
{
extern int errno, sys_nerr;
extern char *sys_errlist[];

fprintf(stderr, "ERROR: %s (%d", msg, errno);
if (errno >0 && errno< sys_nerr)
fprintf(stderr, "; %s)\n", sys_errlist[errno]);
else
fprintf(stderr, ")\n");
exit(1);
}
short nlock(name) /*上锁过程 */
char *name;
{ char *path, *lockpath();
int fd, tries;
extern int errno;
short unlink_result;

path=lockpath(name); /*制锁 */
unlink_result=unlink(path); /*判断是否已经上锁 */
fd=creat(path, 0); /*上锁 */
if (fd==-1 || close(fd)==-1)
syserr("nlock");
if (unlink_result==-1)
return 0xff;
return (0);
}
void nunlock(name) /*解锁 */
char *name;
{ char *lockpath();
if (unlink(lockpath(name))==-1)
syserr("nunlock");
}
static char *lockpath(name) /*制锁的过程 */
char *name;
{ static char path[20];
char *strcat();

strcpy(path, name);
return(strcat(path, ".lok"));
}
int main(argc, argv)
int argc;
char *argv[];
{ if (argc!=2)
{ printf("Usage: %s filename\n\r", argv[0]);
return(1);
}
if (strcmp(argv[0], "lockf")==0)
if (!nlock(argv[1]))
{ printf("You can not add the same lock twice!\r\n");
return(2);
}
if (strcmp(argv[0], "unlockf")==0)
nunlock(argv[1]);
return(0);
}
本程序的用法是:
lockf 源文件名

unlockf 源文件名

---- 要 真 正 实 现 信 号 灯 机 制, 我 们 还 必 须 准 备 一 个 简 单 的script 文 件signal:


if lockf $1
$1 注2
unlockf
else
echo “Error: Another $1 is running.”
fi

---- 这 样 我 们 在 运 行 文 本 编 辑 器dtpad 时, 输 入 下 列 命 令:

---- signal dtpad

---- 反 过 来, 对 于 前 面 提 到 的netscape 程 序, 也 可 以 通 过 编 写 一 个script 文 件supernet 实 现 多 个 进 程 同 时 运 行:


netscape &
rm /.netscape/lock

---- 注1: 还 有 一 种 方 法, 只 适 用 于 普 通 用 户: 在creat 创 建 一 个 新 文 件 时, 即 使 权 限 实 参(permission argument) 不 允 许 写, 该 文 件 也 被 打 开 用 作 写。 但creat 在 截 断 一 个 现 存 文 件 时, 若 无 写 权 限(write permission), 则 失 败。 这 样 就 可 以 只 通 过creat 系 统 调 用 实 现 文 件 信 号 灯 机 制。 但 这 种 做 法 有 一 个 很 明 显 的 缺 点, 就 是 不 适 用 于 超 级 用 户, 因 为 对 于 超 级 用 户 没 有 不 允 许 写 的 东 西。

---- 注2: 这 不 适 于 带& 符 号 的 后 台 进 程。

---- UNIX 系 统 的 文 件 信 号 灯 机 制

---- 作 为 一 个 多 用 户、 多 任 务 的 操 作 系 统,UNIX 允 许 某 个 程 序 同 时 运 行 多 个 进 程。 但 有 时 又 由 于 系 统 资 源 等 因 素 的 制 约, 要 求 一 次 只 能 有 一 个 进 程 在 运 行。 例 如 在Digital UNIX 下 运 行 第 二 个Netscape 进 程 时, 系 统 报 告 如 下 错 误 信 息:

---- Netscape has detected a /.netscape/lock file.

---- This may indicate that another user is running Netscape using your /.netscape files.

---- 实 际 上, 第 一 个Netscape 进 程 在 运 行 时, 加 了 一 把 锁, 禁 止 其 他Netscape 进 程 启 动。 当 它 结 束 时, 把 锁 打 开, 其 他 进 程 才 能 进 入。 这 就 是UNIX 的 信 号 灯 机 制。

---- 而Netscape 是 用 文 件 作 为 信 号 灯 的。 在 运 行 前, 先 检 查 文 件/.netscape/lock 是 否 存 在: 若 存 在, 表 明 锁 已 挂 上, 新 进 程 不 能 运 行, 只 好 等 待; 若 没 有, 说 明 锁 已 打 开, 可 以 运 行 了。

---- 在 掌 握 了 文 件 信 号 灯 的 机 理 后, 可 以 自 行 设 计 一 套 万 能 加 锁 解 锁 程 序, 为 每 个 程 序 配 上 各 自 的 锁 和 钥 匙。 并 且 使 用 零 字 节 长 度 的 文 件 当 锁, 减 少 系 统 开 销。

---- 我 们 用creat 和unlink 两 个 系 统 调 用 实 现 加 解 锁 和 检 测 操 作。 一 个 进 程 运 行 之 前, 先 通 过unlink 检 测 锁 文 件 是 否 存 在 注1。unlink 系 统 调 用 从 一 个 目 录 中 删 去 一 个 文 件 链, 若 成 功 则 返 回0, 表 示 确 有 文 件 存 在; 若 失 败, 表 明 文 件 不 存 在, 返 回-1。 如 果 还 没 有 上 锁, 就 要 用creat 系 统 调 用 创 建 锁 文 件; 若 锁 已 挂 上, 虽 然 进 程 并 未 运 行, 但 unlink 无 疑 会 删 除 锁 文 件, 所 以 也 要 用creat 来 恢 复。creat 系 统 调 用 创 建 一 个 新 文 件, 函 数 标 题 如 下:


int creat(path, perms) /* create file */
char *path; /* path name */
int perms; /* permission bits */

---- 其 中path 表 示 路 径 加 文 件 名,perms 是10 位 的 文 件 权 限 描 述 字, 在 加 锁 程 序 中 取0。 文 件 在 刚 创 建 时, 初 始 长 度 为 零 字 节, 用 它 来 做 锁 文 件, 可 以 最 大 限 度 地 降 低 系 统 开 销。

---- 锁 文 件 规 定 为: 源 文 件 名+“.lok”。 这 样 一 来, 就 真 正 做 到 了 一 个 程 序 配 一 把 锁。

---- 下 面 就 列 出 加 锁 和 解 锁 的 程 序 清 单。 我 们 用 同 样 的 程 序 完 成 这 两 种 完 全 互 斥 的 操 作, 区 别 在 于 命 令 名 的 不 同。 在C 语 言 源 程 序 里, 变 量argv[0] 表 示 命 令 名,“lockf” 是 上 锁,“unlockf” 是 解 锁。

---- 程 序LOCKF.C 暨UNLOCKF.C 的 源 代 码

#include < stdio.h >
#include < errno.h >
#include < fcntl.h >
#include < cdatyp.h >
void syserr(msg) /*打印系统调用错误信息并中止 */
char *msg;
{
extern int errno, sys_nerr;
extern char *sys_errlist[];

fprintf(stderr, "ERROR: %s (%d", msg, errno);
if (errno >0 && errno< sys_nerr)
fprintf(stderr, "; %s)\n", sys_errlist[errno]);
else
fprintf(stderr, ")\n");
exit(1);
}
short nlock(name) /*上锁过程 */
char *name;
{ char *path, *lockpath();
int fd, tries;
extern int errno;
short unlink_result;

path=lockpath(name); /*制锁 */
unlink_result=unlink(path); /*判断是否已经上锁 */
fd=creat(path, 0); /*上锁 */
if (fd==-1 || close(fd)==-1)
syserr("nlock");
if (unlink_result==-1)
return 0xff;
return (0);
}
void nunlock(name) /*解锁 */
char *name;
{ char *lockpath();
if (unlink(lockpath(name))==-1)
syserr("nunlock");
}
static char *lockpath(name) /*制锁的过程 */
char *name;
{ static char path[20];
char *strcat();

strcpy(path, name);
return(strcat(path, ".lok"));
}
int main(argc, argv)
int argc;
char *argv[];
{ if (argc!=2)
{ printf("Usage: %s filename\n\r", argv[0]);
return(1);
}
if (strcmp(argv[0], "lockf")==0)
if (!nlock(argv[1]))
{ printf("You can not add the same lock twice!\r\n");
return(2);
}
if (strcmp(argv[0], "unlockf")==0)
nunlock(argv[1]);
return(0);
}
本程序的用法是:
lockf 源文件名

unlockf 源文件名

---- 要 真 正 实 现 信 号 灯 机 制, 我 们 还 必 须 准 备 一 个 简 单 的script 文 件signal:


if lockf $1
$1 注2
unlockf
else
echo “Error: Another $1 is running.”
fi

---- 这 样 我 们 在 运 行 文 本 编 辑 器dtpad 时, 输 入 下 列 命 令:

---- signal dtpad

---- 反 过 来, 对 于 前 面 提 到 的netscape 程 序, 也 可 以 通 过 编 写 一 个script 文 件supernet 实 现 多 个 进 程 同 时 运 行:


netscape &
rm /.netscape/lock

---- 注1: 还 有 一 种 方 法, 只 适 用 于 普 通 用 户: 在creat 创 建 一 个 新 文 件 时, 即 使 权 限 实 参(permission argument) 不 允 许 写, 该 文 件 也 被 打 开 用 作 写。 但creat 在 截 断 一 个 现 存 文 件 时, 若 无 写 权 限(write permission), 则 失 败。 这 样 就 可 以 只 通 过creat 系 统 调 用 实 现 文 件 信 号 灯 机 制。 但 这 种 做 法 有 一 个 很 明 显 的 缺 点, 就 是 不 适 用 于 超 级 用 户, 因 为 对 于 超 级 用 户 没 有 不 允 许 写 的 东 西。

---- 注2: 这 不 适 于 带& 符 号 的 后 台 进 程。

---- UNIX 系 统 的 文 件 信 号 灯 机 制

---- 作 为 一 个 多 用 户、 多 任 务 的 操 作 系 统,UNIX 允 许 某 个 程 序 同 时 运 行 多 个 进 程。 但 有 时 又 由 于 系 统 资 源 等 因 素 的 制 约, 要 求 一 次 只 能 有 一 个 进 程 在 运 行。 例 如 在Digital UNIX 下 运 行 第 二 个Netscape 进 程 时, 系 统 报 告 如 下 错 误 信 息:

---- Netscape has detected a /.netscape/lock file.

---- This may indicate that another user is running Netscape using your /.netscape files.

---- 实 际 上, 第 一 个Netscape 进 程 在 运 行 时, 加 了 一 把 锁, 禁 止 其 他Netscape 进 程 启 动。 当 它 结 束 时, 把 锁 打 开, 其 他 进 程 才 能 进 入。 这 就 是UNIX 的 信 号 灯 机 制。

---- 而Netscape 是 用 文 件 作 为 信 号 灯 的。 在 运 行 前, 先 检 查 文 件/.netscape/lock 是 否 存 在: 若 存 在, 表 明 锁 已 挂 上, 新 进 程 不 能 运 行, 只 好 等 待; 若 没 有, 说 明 锁 已 打 开, 可 以 运 行 了。

---- 在 掌 握 了 文 件 信 号 灯 的 机 理 后, 可 以 自 行 设 计 一 套 万 能 加 锁 解 锁 程 序, 为 每 个 程 序 配 上 各 自 的 锁 和 钥 匙。 并 且 使 用 零 字 节 长 度 的 文 件 当 锁, 减 少 系 统 开 销。

---- 我 们 用creat 和unlink 两 个 系 统 调 用 实 现 加 解 锁 和 检 测 操 作。 一 个 进 程 运 行 之 前, 先 通 过unlink 检 测 锁 文 件 是 否 存 在 注1。unlink 系 统 调 用 从 一 个 目 录 中 删 去 一 个 文 件 链, 若 成 功 则 返 回0, 表 示 确 有 文 件 存 在; 若 失 败, 表 明 文 件 不 存 在, 返 回-1。 如 果 还 没 有 上 锁, 就 要 用creat 系 统 调 用 创 建 锁 文 件; 若 锁 已 挂 上, 虽 然 进 程 并 未 运 行, 但 unlink 无 疑 会 删 除 锁 文 件, 所 以 也 要 用creat 来 恢 复。creat 系 统 调 用 创 建 一 个 新 文 件, 函 数 标 题 如 下:


int creat(path, perms) /* create file */
char *path; /* path name */
int perms; /* permission bits */

---- 其 中path 表 示 路 径 加 文 件 名,perms 是10 位 的 文 件 权 限 描 述 字, 在 加 锁 程 序 中 取0。 文 件 在 刚 创 建 时, 初 始 长 度 为 零 字 节, 用 它 来 做 锁 文 件, 可 以 最 大 限 度 地 降 低 系 统 开 销。

---- 锁 文 件 规 定 为: 源 文 件 名+“.lok”。 这 样 一 来, 就 真 正 做 到 了 一 个 程 序 配 一 把 锁。

---- 下 面 就 列 出 加 锁 和 解 锁 的 程 序 清 单。 我 们 用 同 样 的 程 序 完 成 这 两 种 完 全 互 斥 的 操 作, 区 别 在 于 命 令 名 的 不 同。 在C 语 言 源 程 序 里, 变 量argv[0] 表 示 命 令 名,“lockf” 是 上 锁,“unlockf” 是 解 锁。

---- 程 序LOCKF.C 暨UNLOCKF.C 的 源 代 码


#include < stdio.h >
#include < errno.h >
#include < fcntl.h >
#include < cdatyp.h >
void syserr(msg) /*打印系统调用错误信息并中止 */
char *msg;
{
extern int errno, sys_nerr;
extern char *sys_errlist[];

fprintf(stderr, "ERROR: %s (%d", msg, errno);
if (errno >0 && errno< sys_nerr)
fprintf(stderr, "; %s)\n", sys_errlist[errno]);
else
fprintf(stderr, ")\n");
exit(1);
}
short nlock(name) /*上锁过程 */
char *name;
{ char *path, *lockpath();
int fd, tries;
extern int errno;
short unlink_result;

path=lockpath(name); /*制锁 */
unlink_result=unlink(path); /*判断是否已经上锁 */
fd=creat(path, 0); /*上锁 */
if (fd==-1 || close(fd)==-1)
syserr("nlock");
if (unlink_result==-1)
return 0xff;
return (0);
}
void nunlock(name) /*解锁 */
char *name;
{ char *lockpath();
if (unlink(lockpath(name))==-1)
syserr("nunlock");
}
static char *lockpath(name) /*制锁的过程 */
char *name;
{ static char path[20];
char *strcat();

strcpy(path, name);
return(strcat(path, ".lok"));
}
int main(argc, argv)
int argc;
char *argv[];
{ if (argc!=2)
{ printf("Usage: %s filename\n\r", argv[0]);
return(1);
}
if (strcmp(argv[0], "lockf")==0)
if (!nlock(argv[1]))
{ printf("You can not add the same lock twice!\r\n");
return(2);
}
if (strcmp(argv[0], "unlockf")==0)
nunlock(argv[1]);
return(0);
}
本程序的用法是:
lockf 源文件名

unlockf 源文件名

---- 要 真 正 实 现 信 号 灯 机 制, 我 们 还 必 须 准 备 一 个 简 单 的script 文 件signal:


if lockf $1
$1 注2
unlockf
else
echo “Error: Another $1 is running.”
fi

---- 这 样 我 们 在 运 行 文 本 编 辑 器dtpad 时, 输 入 下 列 命 令:

---- signal dtpad

---- 反 过 来, 对 于 前 面 提 到 的netscape 程 序, 也 可 以 通 过 编 写 一 个script 文 件supernet 实 现 多 个 进 程 同 时 运 行:


netscape &
rm /.netscape/lock

---- 注1: 还 有 一 种 方 法, 只 适 用 于 普 通 用 户: 在creat 创 建 一 个 新 文 件 时, 即 使 权 限 实 参(permission argument) 不 允 许 写, 该 文 件 也 被 打 开 用 作 写。 但creat 在 截 断 一 个 现 存 文 件 时, 若 无 写 权 限(write permission), 则 失 败。 这 样 就 可 以 只 通 过creat 系 统 调 用 实 现 文 件 信 号 灯 机 制。 但 这 种 做 法 有 一 个 很 明 显 的 缺 点, 就 是 不 适 用 于 超 级 用 户, 因 为 对 于 超 级 用 户 没 有 不 允 许 写 的 东 西。

---- 注2: 这 不 适 于 带& 符 号 的 后 台 进 程。

---- UNIX 系 统 的 文 件 信 号 灯 机 制

---- 作 为 一 个 多 用 户、 多 任 务 的 操 作 系 统,UNIX 允 许 某 个 程 序 同 时 运 行 多 个 进 程。 但 有 时 又 由 于 系 统 资 源 等 因 素 的 制 约, 要 求 一 次 只 能 有 一 个 进 程 在 运 行。 例 如 在Digital UNIX 下 运 行 第 二 个Netscape 进 程 时, 系 统 报 告 如 下 错 误 信 息:

---- Netscape has detected a /.netscape/lock file.

---- This may indicate that another user is running Netscape using your /.netscape files.

---- 实 际 上, 第 一 个Netscape 进 程 在 运 行 时, 加 了 一 把 锁, 禁 止 其 他Netscape 进 程 启 动。 当 它 结 束 时, 把 锁 打 开, 其 他 进 程 才 能 进 入。 这 就 是UNIX 的 信 号 灯 机 制。

---- 而Netscape 是 用 文 件 作 为 信 号 灯 的。 在 运 行 前, 先 检 查 文 件/.netscape/lock 是 否 存 在: 若 存 在, 表 明 锁 已 挂 上, 新 进 程 不 能 运 行, 只 好 等 待; 若 没 有, 说 明 锁 已 打 开, 可 以 运 行 了。

---- 在 掌 握 了 文 件 信 号 灯 的 机 理 后, 可 以 自 行 设 计 一 套 万 能 加 锁 解 锁 程 序, 为 每 个 程 序 配 上 各 自 的 锁 和 钥 匙。 并 且 使 用 零 字 节 长 度 的 文 件 当 锁, 减 少 系 统 开 销。

---- 我 们 用creat 和unlink 两 个 系 统 调 用 实 现 加 解 锁 和 检 测 操 作。 一 个 进 程 运 行 之 前, 先 通 过unlink 检 测 锁 文 件 是 否 存 在 注1。unlink 系 统 调 用 从 一 个 目 录 中 删 去 一 个 文 件 链, 若 成 功 则 返 回0, 表 示 确 有 文 件 存 在; 若 失 败, 表 明 文 件 不 存 在, 返 回-1。 如 果 还 没 有 上 锁, 就 要 用creat 系 统 调 用 创 建 锁 文 件; 若 锁 已 挂 上, 虽 然 进 程 并 未 运 行, 但 unlink 无 疑 会 删 除 锁 文 件, 所 以 也 要 用creat 来 恢 复。creat 系 统 调 用 创 建 一 个 新 文 件, 函 数 标 题 如 下:


int creat(path, perms) /* create file */
char *path; /* path name */
int perms; /* permission bits */

---- 其 中path 表 示 路 径 加 文 件 名,perms 是10 位 的 文 件 权 限 描 述 字, 在 加 锁 程 序 中 取0。 文 件 在 刚 创 建 时, 初 始 长 度 为 零 字 节, 用 它 来 做 锁 文 件, 可 以 最 大 限 度 地 降 低 系 统 开 销。

---- 锁 文 件 规 定 为: 源 文 件 名+“.lok”。 这 样 一 来, 就 真 正 做 到 了 一 个 程 序 配 一 把 锁。

---- 下 面 就 列 出 加 锁 和 解 锁 的 程 序 清 单。 我 们 用 同 样 的 程 序 完 成 这 两 种 完 全 互 斥 的 操 作, 区 别 在 于 命 令 名 的 不 同。 在C 语 言 源 程 序 里, 变 量argv[0] 表 示 命 令 名,“lockf” 是 上 锁,“unlockf” 是 解 锁。

---- 程 序LOCKF.C 暨UNLOCKF.C 的 源 代 码


#include < stdio.h >
#include < errno.h >
#include < fcntl.h >
#include < cdatyp.h >
void syserr(msg) /*打印系统调用错误信息并中止 */
char *msg;
{
extern int errno, sys_nerr;
extern char *sys_errlist[];

fprintf(stderr, "ERROR: %s (%d", msg, errno);
if (errno >0 && errno< sys_nerr)
fprintf(stderr, "; %s)\n", sys_errlist[errno]);
else
fprintf(stderr, ")\n");
exit(1);
}
short nlock(name) /*上锁过程 */
char *name;
{ char *path, *lockpath();
int fd, tries;
extern int errno;
short unlink_result;

path=lockpath(name); /*制锁 */
unlink_result=unlink(path); /*判断是否已经上锁 */
fd=creat(path, 0); /*上锁 */
if (fd==-1 || close(fd)==-1)
syserr("nlock");
if (unlink_result==-1)
return 0xff;
return (0);
}
void nunlock(name) /*解锁 */
char *name;
{ char *lockpath();
if (unlink(lockpath(name))==-1)
syserr("nunlock");
}
static char *lockpath(name) /*制锁的过程 */
char *name;
{ static char path[20];
char *strcat();

strcpy(path, name);
return(strcat(path, ".lok"));
}
int main(argc, argv)
int argc;
char *argv[];
{ if (argc!=2)
{ printf("Usage: %s filename\n\r", argv[0]);
return(1);
}
if (strcmp(argv[0], "lockf")==0)
if (!nlock(argv[1]))
{ printf("You can not add the same lock twice!\r\n");
return(2);
}
if (strcmp(argv[0], "unlockf")==0)
nunlock(argv[1]);
return(0);
}
本程序的用法是:
lockf 源文件名

unlockf 源文件名

---- 要 真 正 实 现 信 号 灯 机 制, 我 们 还 必 须 准 备 一 个 简 单 的script 文 件signal:


if lockf $1
$1 注2
unlockf
else
echo “Error: Another $1 is running.”
fi

---- 这 样 我 们 在 运 行 文 本 编 辑 器dtpad 时, 输 入 下 列 命 令:

---- signal dtpad

---- 反 过 来, 对 于 前 面 提 到 的netscape 程 序, 也 可 以 通 过 编 写 一 个script 文 件supernet 实 现 多 个 进 程 同 时 运 行:


netscape &
rm /.netscape/lock

---- 注1: 还 有 一 种 方 法, 只 适 用 于 普 通 用 户: 在creat 创 建 一 个 新 文 件 时, 即 使 权 限 实 参(permission argument) 不 允 许 写, 该 文 件 也 被 打 开 用 作 写。 但creat 在 截 断 一 个 现 存 文 件 时, 若 无 写 权 限(write permission), 则 失 败。 这 样 就 可 以 只 通 过creat 系 统 调 用 实 现 文 件 信 号 灯 机 制。 但 这 种 做 法 有 一 个 很 明 显 的 缺 点, 就 是 不 适 用 于 超 级 用 户, 因 为 对 于 超 级 用 户 没 有 不 允 许 写 的 东 西。

---- 注2: 这 不 适 于 带& 符 号 的 后 台 进 程。

---- UNIX 系 统 的 文 件 信 号 灯 机 制

---- 作 为 一 个 多 用 户、 多 任 务 的 操 作 系 统,UNIX 允 许 某 个 程 序 同 时 运 行 多 个 进 程。 但 有 时 又 由 于 系 统 资 源 等 因 素 的 制 约, 要 求 一 次 只 能 有 一 个 进 程 在 运 行。 例 如 在Digital UNIX 下 运 行 第 二 个Netscape 进 程 时, 系 统 报 告 如 下 错 误 信 息:

---- Netscape has detected a /.netscape/lock file.

---- This may indicate that another user is running Netscape using your /.netscape files.

---- 实 际 上, 第 一 个Netscape 进 程 在 运 行 时, 加 了 一 把 锁, 禁 止 其 他Netscape 进 程 启 动。 当 它 结 束 时, 把 锁 打 开, 其 他 进 程 才 能 进 入。 这 就 是UNIX 的 信 号 灯 机 制。

---- 而Netscape 是 用 文 件 作 为 信 号 灯 的。 在 运 行 前, 先 检 查 文 件/.netscape/lock 是 否 存 在: 若 存 在, 表 明 锁 已 挂 上, 新 进 程 不 能 运 行, 只 好 等 待; 若 没 有, 说 明 锁 已 打 开, 可 以 运 行 了。

---- 在 掌 握 了 文 件 信 号 灯 的 机 理 后, 可 以 自 行 设 计 一 套 万 能 加 锁 解 锁 程 序, 为 每 个 程 序 配 上 各 自 的 锁 和 钥 匙。 并 且 使 用 零 字 节 长 度 的 文 件 当 锁, 减 少 系 统 开 销。

---- 我 们 用creat 和unlink 两 个 系 统 调 用 实 现 加 解 锁 和 检 测 操 作。 一 个 进 程 运 行 之 前, 先 通 过unlink 检 测 锁 文 件 是 否 存 在 注1。unlink 系 统 调 用 从 一 个 目 录 中 删 去 一 个 文 件 链, 若 成 功 则 返 回0, 表 示 确 有 文 件 存 在; 若 失 败, 表 明 文 件 不 存 在, 返 回-1。 如 果 还 没 有 上 锁, 就 要 用creat 系 统 调 用 创 建 锁 文 件; 若 锁 已 挂 上, 虽 然 进 程 并 未 运 行, 但 unlink 无 疑 会 删 除 锁 文 件, 所 以 也 要 用creat 来 恢 复。creat 系 统 调 用 创 建 一 个 新 文 件, 函 数 标 题 如 下:


int creat(path, perms) /* create file */
char *path; /* path name */
int perms; /* permission bits */

---- 其 中path 表 示 路 径 加 文 件 名,perms 是10 位 的 文 件 权 限 描 述 字, 在 加 锁 程 序 中 取0。 文 件 在 刚 创 建 时, 初 始 长 度 为 零 字 节, 用 它 来 做 锁 文 件, 可 以 最 大 限 度 地 降 低 系 统 开 销。

---- 锁 文 件 规 定 为: 源 文 件 名+“.lok”。 这 样 一 来, 就 真 正 做 到 了 一 个 程 序 配 一 把 锁。

---- 下 面 就 列 出 加 锁 和 解 锁 的 程 序 清 单。 我 们 用 同 样 的 程 序 完 成 这 两 种 完 全 互 斥 的 操 作, 区 别 在 于 命 令 名 的 不 同。 在C 语 言 源 程 序 里, 变 量argv[0] 表 示 命 令 名,“lockf” 是 上 锁,“unlockf” 是 解 锁。

---- 程 序LOCKF.C 暨UNLOCKF.C 的 源 代 码


#include < stdio.h >
#include < errno.h >
#include < fcntl.h >
#include < cdatyp.h >
void syserr(msg) /*打印系统调用错误信息并中止 */
char *msg;
{
extern int errno, sys_nerr;
extern char *sys_errlist[];

fprintf(stderr, "ERROR: %s (%d", msg, errno);
if (errno >0 && errno< sys_nerr)
fprintf(stderr, "; %s)\n", sys_errlist[errno]);
else
fprintf(stderr, ")\n");
exit(1);
}
short nlock(name) /*上锁过程 */
char *name;
{ char *path, *lockpath();
int fd, tries;
extern int errno;
short unlink_result;

path=lockpath(name); /*制锁 */
unlink_result=unlink(path); /*判断是否已经上锁 */
fd=creat(path, 0); /*上锁 */
if (fd==-1 || close(fd)==-1)
syserr("nlock");
if (unlink_result==-1)
return 0xff;
return (0);
}
void nunlock(name) /*解锁 */
char *name;
{ char *lockpath();
if (unlink(lockpath(name))==-1)
syserr("nunlock");
}
static char *lockpath(name) /*制锁的过程 */
char *name;
{ static char path[20];
char *strcat();

strcpy(path, name);
return(strcat(path, ".lok"));
}
int main(argc, argv)
int argc;
char *argv[];
{ if (argc!=2)
{ printf("Usage: %s filename\n\r", argv[0]);
return(1);
}
if (strcmp(argv[0], "lockf")==0)
if (!nlock(argv[1]))
{ printf("You can not add the same lock twice!\r\n");
return(2);
}
if (strcmp(argv[0], "unlockf")==0)
nunlock(argv[1]);
return(0);
}
本程序的用法是:
lockf 源文件名

unlockf 源文件名

---- 要 真 正 实 现 信 号 灯 机 制, 我 们 还 必 须 准 备 一 个 简 单 的script 文 件signal:


if lockf $1
$1 注2
unlockf
else
echo “Error: Another $1 is running.”
fi

---- 这 样 我 们 在 运 行 文 本 编 辑 器dtpad 时, 输 入 下 列 命 令:

---- signal dtpad

---- 反 过 来, 对 于 前 面 提 到 的netscape 程 序, 也 可 以 通 过 编 写 一 个script 文 件supernet 实 现 多 个 进 程 同 时 运 行:


netscape &
rm /.netscape/lock

---- 注1: 还 有 一 种 方 法, 只 适 用 于 普 通 用 户: 在creat 创 建 一 个 新 文 件 时, 即 使 权 限 实 参(permission argument) 不 允 许 写, 该 文 件 也 被 打 开 用 作 写。 但creat 在 截 断 一 个 现 存 文 件 时, 若 无 写 权 限(write permission), 则 失 败。 这 样 就 可 以 只 通 过creat 系 统 调 用 实 现 文 件 信 号 灯 机 制。 但 这 种 做 法 有 一 个 很 明 显 的 缺 点, 就 是 不 适 用 于 超 级 用 户, 因 为 对 于 超 级 用 户 没 有 不 允 许 写 的 东 西。

---- 注2: 这 不 适 于 带& 符 号 的 后 台 进 程。

---- UNIX 系 统 的 文 件 信 号 灯 机 制

---- 作 为 一 个 多 用 户、 多 任 务 的 操 作 系 统,UNIX 允 许 某 个 程 序 同 时 运 行 多 个 进 程。 但 有 时 又 由 于 系 统 资 源 等 因 素 的 制 约, 要 求 一 次 只 能 有 一 个 进 程 在 运 行。 例 如 在Digital UNIX 下 运 行 第 二 个Netscape 进 程 时, 系 统 报 告 如 下 错 误 信 息:

---- Netscape has detected a /.netscape/lock file.

---- This may indicate that another user is running Netscape using your /.netscape files.

---- 实 际 上, 第 一 个Netscape 进 程 在 运 行 时, 加 了 一 把 锁, 禁 止 其 他Netscape 进 程 启 动。 当 它 结 束 时, 把 锁 打 开, 其 他 进 程 才 能 进 入。 这 就 是UNIX 的 信 号 灯 机 制。

---- 而Netscape 是 用 文 件 作 (http://www.fanqiang.com)     进入【UNIX论坛


相关文章
 

★  樊强制作 欢迎分享  ★