【发布时间】:2019-01-21 14:12:00
【问题描述】:
最近调用popen遇到了麻烦,好像不是线程安全的。
以下是源代码链接中的代码sn-p:http://androidxref.com/9.0.0_r3/xref/bionic/libc/upstream-netbsd/lib/libc/gen/popen.c
static struct pid {
struct pid *next;
FILE *fp;
int fd;
pid_t pid;
} *pidlist;
static rwlock_t pidlist_lock = RWLOCK_INITIALIZER;
FILE *
popen(const char *command, const char *type)
{
struct pid *cur, *old;
...
pipe2(pdes, flags) // A
...
(void)rwlock_rdlock(&pidlist_lock); // C
...
switch (pid = vfork()) { // C.1
case 0: /* Child. */
...
_exit(127);
/* NOTREACHED */
}
/* Parent; */
...
/* Link into list of file descriptors. */
cur->fp = iop;
cur->pid = pid;
cur->next = pidlist; // D
pidlist = cur; // E
(void)rwlock_unlock(&pidlist_lock); // F
...
}
观察上面的代码,它在 C 处获得了一个读锁,但在作用域内,它在 E 处做了一些写操作。因此,可能会有多个读线程正在写入变量“pidlist”同一时间。
有人知道这是否是一个真正的问题吗?
【问题讨论】:
-
vfork()之后的下一行是什么?如果它不是对exec...()函数之一的调用,那将是一件坏事。一般来说,在创建一个或多个新线程之后分叉一个 Linux 进程也是一件坏事,但我不知道当你谈论vfork()/exec()时该规则如何适用。 -
一目了然,我同意。我看不出有什么会阻止两个不同的
struct pid节点被初始化并竞相设置新的pidlist值。这将导致两个节点之一被排除在列表之外。在我看来它应该是一个写锁。
标签: multithreading concurrency thread-safety popen