POSIX和C11都要求流具有关联的锁,以防止数据争用和交织。 POSIX文档flockfile()
和相关功能允许线程安全的I / O跨越多个调用。有等效的C函数吗?我不记得一个,也没有找到一个提到的,这并不一定意味着一个不存在。
在相关说明中,可以安全地假定任何声称POSIX一致性的实现在使用C11线程时都遵守flockfile()
。h吗?我认为大多数支持thread.h的主要POSIX兼容C实现都是通过在pthread上构建来实现的,这意味着这种假设通常是安全的。但是,多线程很难,了解异常将很有帮助。
答案 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);
}
}