使用 sprintf 和 printf 时 C 线程安全 locale/encoding

C Thread safe locale/encoding when using sprintf and printf

这个问题与我目前想做的事情无关,但我在阅读 sprintf() printf() 和 [= 的 (GNU/Linux/ISO-C) 文档时想知道的事情13=].

假设问题:

想象一个 多线程 应用程序,它使用 printf/scanf 系列在一个线程上面向用户的文本输出,并且 printf/scanf 在 另一个线程 上用于文件甚至网络 I/O。现在想象这样一个场景,该应用程序需要对不同种类的 I/O 使用 不同的 encodings/locales。 设置 locale/encoding 的方法是使用 setlocale(),它在 Linux Programmer's Manual.

中明确标记为 "MT-Unsafe"

ISO/IEC 9899:2018 在 7.11.1.1

有以下内容要说

A call to the setlocale function may introduce a data race with other calls to the setlocale function or with calls to functions that are affected by the current locale. The implementation shall behave as if no library function calls the setlocale function.

据我所知,这使得标准 C 没有标准方法来处理前面描述的情况。 (这不涉及线程之间不必要的同步,否则不会干扰)

请注意,POSIX 指定了 uselocale() 函数,这是专门为此制作的。 但这不是嵌入式或 tuly 多平台代码的解决方案。

问题

长话短说;博士: 如何处理多线程编码(POSIX之外)?

也许通过使用或多或少的标准互斥锁?例如。如 How to Use C Mutex Lock Examples for Linux Thread Synchronization 所述:

简介

我们雇用 pthread.h。线程管理将是:

...
pthread_t tid[2];
pthread_create(&(tid[i]), NULL, &doSomeThing, NULL);
pthread_join(tid[0], NULL);
pthread_join(tid[1], NULL);
...

初始化一个互斥量,然后通过调用以下两个函数实现锁定:

int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);
int pthread_mutex_lock(pthread_mutex_t *mutex);

可以通过调用以下函数解锁和销毁互斥量:

int pthread_mutex_unlock(pthread_mutex_t *mutex);
int pthread_mutex_destroy(pthread_mutex_t *mutex);

实例

让我们看一段代码,其中互斥量用于线程同步:

#include<stdio.h>
#include<string.h>
#include<pthread.h>
#include<stdlib.h>
#include<unistd.h>

pthread_t tid[2];
int counter;
pthread_mutex_t lock;

void* doSomeThing(void *arg)
{
    pthread_mutex_lock(&lock);

    unsigned long i = 0;
    counter += 1;
    printf("\n Job %d started\n", counter);

    for(i=0; i<(0xFFFFFFFF);i++);

    printf("\n Job %d finished\n", counter);

    pthread_mutex_unlock(&lock);

    return NULL;
}

int main(void)
{
    int i = 0;
    int err;

    if (pthread_mutex_init(&lock, NULL) != 0)
    {
        printf("\n mutex init failed\n");
        return 1;
    }

    while(i < 2)
    {
        err = pthread_create(&(tid[i]), NULL, &doSomeThing, NULL);
        if (err != 0)
            printf("\ncan't create thread :[%s]", strerror(err));
        i++;
    }

    pthread_join(tid[0], NULL);
    pthread_join(tid[1], NULL);
    pthread_mutex_destroy(&lock);

    return 0;
}

一旦程序变为多线程,您就根本无法在程序中安全地使用 setlocale。如果您需要多个语言环境,则需要 newlocale/uselocale API 用于线程本地或第一个 class 语言环境对象,而不是 setlocale.