C11是否等同于POSIX flockfile()?

时间:2019-02-27 03:38:33

标签: c thread-safety posix

POSIX和C11都要求流具有关联的锁,以防止数据争用和交织。 POSIX文档flockfile()和相关功能允许线程安全的I / O跨越多个调用。有等效的C函数吗?我不记得一个,也没有找到一个提到的,这并不一定意味着一个不存在。

在相关说明中,可以安全地假定任何声称POSIX一致性的实现在使用C11线程时都遵守flockfile()。h吗?我认为大多数支持thread.h的主要POSIX兼容C实现都是通过在pthread上构建来实现的,这意味着这种假设通常是安全的。但是,多线程很难,了解异常将很有帮助。

2 个答案:

答案 0 :(得分:2)

<块引用>

POSIX 和 C11 都要求流具有关联的锁,以防止数据竞争和交错。

是的,但是对锁的特定形式没有要求,C 也没有要求使程序可以直接访问该锁,也没有任何标准机制可以这样做。

<块引用>

POSIX 记录了 flockfile() 和相关函数,以允许线程安全 I/O 跨越多个调用。是否有等效的 C 函数?

没有已发布的 C 语言规范版本记录了 flockfile()ftrylockfile()funlockfile() 的类似物。一个严格符合 C11 或 C17 的程序想要防止被交错的不同线程调用 I/O 函数将(因为它严格符合)在没有定义宏 {{1} }.这样的程序可以为此目的使用该库的互斥锁实现。没有标准方法可以直接访问与单个 __STDC_NO_THREADS__ 对象直接关联的任何锁。

<块引用>

在相关说明中,假设任何声明声称的实现是否安全 POSIX 一致性在使用 C11 线程时会尊重 flockfile() 吗?

据我所知,POSIX C 语言接口仍然专门根据 C99 定义,因此 POSIX 对 C11 线程视而不见。从这个意义上说,不,假设 POSIX 关于线程行为的规定将适用于 C11 线程是不安全的。

<块引用>

我 认为大多数支持 POSIX 的主要 C 实现 threads.h 是通过在 pthreads 上构建来实现的,这意味着这样一个 假设通常是安全的。然而,多线程很难,而且它 了解异常会很有帮助。

在实践中,我期望 POSIX 系统上的 C11 和更高版本的实现将确保 C11 线程实际上确实具有 POSIX 线程的语义,无论是通过在 POSIX 线程之上实现 C11 线程还是通过其他方式。因此,希望 C11 线程能够根据需要与 FILE 进行互操作是合理的,但省略专门探测该细节的单元测试是不合理的。

另请注意,在这样的上下文中,“通常安全”是一种巧妙的表达“不安全”的方式。

答案 1 :(得分:0)

Stockfish 中的 Windows 实现:

void flockfile(FILE *F)
{
  if ((F >= (&__iob_func()[0])) && (F <= (&__iob_func()[_IOB_ENTRIES-1]))) {
    _lock(_STREAM_LOCKS + (int)(F - (&__iob_func()[0])));
    F->_flag |= _IOLOCKED;
  } else
    EnterCriticalSection(&(((_FILEX *)F)->lock));
}

void funlockfile(FILE *F)
{
  if ((F >= (&__iob_func()[0])) && (F <= (&__iob_func()[_IOB_ENTRIES-1]))) {
    F->_flag &= ~_IOLOCKED;
    _unlock(_STREAM_LOCKS + (int)(F - (&__iob_func()[0])));
  } else
    LeaveCriticalSection(&(((_FILEX *)F)->lock));
}

https://github.com/syzygy1/Cfish/blob/5dbf00f9ffae28b0c96a713e897d718204af73e9/src/misc.c#L299

或者 Android 是如何做的:

void
flockfile(FILE * fp)
{
    LockTable*  t = lock_table_lock();
    if (t != NULL) {
        FileLock**  lookup = lock_table_lookup(t, fp);
        FileLock*   lock   = *lookup;
        if (lock == NULL) {
            pthread_mutexattr_t  attr;
            /* create a new node in the hash table */
            lock = malloc(sizeof(*lock));
            if (lock == NULL) {
                lock_table_unlock(t);
                return;
            }
            lock->next        = NULL;
            lock->file        = fp;
            pthread_mutexattr_init(&attr);
            pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
            pthread_mutex_init( &lock->mutex, &attr );
            *lookup           = lock;
        }
        lock_table_unlock(t);
        /* we assume that another thread didn't destroy 'lock'
        * by calling fclose() on the FILE*. This can happen if
        * the client is *really* buggy, but we don't care about
        * such code here.
        */
        pthread_mutex_lock(&lock->mutex);
    }
}

https://source.codeaurora.org/external/gigabyte/qrd-gb-ssss-7225/plain/android/bionic/libc/stdio/flockfile.c