Multithreading et paramètres régionaux

La bibliothèque C Runtime et la bibliothèque standard C++ prennent en charge la modification des paramètres régionaux de votre programme. Cette rubrique traite des problèmes qui surviennent lors de l’utilisation des fonctionnalités de paramètres régionaux des deux bibliothèques dans une application multithread.

Notes

Avec la bibliothèque runtime C, vous pouvez créer des applications multithread à l’aide des fonctions et _beginthreadex des _beginthread fonctions. Cette rubrique couvre uniquement les applications multithread créées à l’aide de ces fonctions. Pour plus d’informations, consultez _beginthread, _beginthreadex.

Pour modifier les paramètres régionaux à l’aide de la bibliothèque runtime C, utilisez la fonction setlocale . Dans les versions précédentes de Visual C++, cette fonction modifie toujours les paramètres régionaux dans l’ensemble de l’application. La définition des paramètres régionaux par thread est désormais prise en charge. Pour ce faire, utilisez la fonction _configthreadlocale . Pour spécifier que setlocale doit uniquement modifier les paramètres régionaux dans le thread actuel, appelez _configthreadlocale(_ENABLE_PER_THREAD_LOCALE) ce thread. À l’inverse, l’appel _configthreadlocale(_DISABLE_PER_THREAD_LOCALE) entraîne l’utilisation des paramètres régionaux globaux et tout appel à setlocale dans ce thread modifie les paramètres régionaux dans tous les threads qui n’ont pas explicitement activé les paramètres régionaux par thread.

Pour modifier les paramètres régionaux à l’aide de la bibliothèque runtime C++, utilisez la classe de paramètres régionaux. En appelant la méthode locale ::global , vous modifiez les paramètres régionaux dans chaque thread qui n’a pas explicitement activé les paramètres régionaux par thread. Pour modifier les paramètres régionaux dans un thread ou une partie d’une application, créez simplement une instance d’un locale objet dans ce thread ou une partie de code.

Remarque

L’appel de paramètres régionaux ::global modifie les paramètres régionaux pour la bibliothèque C++ Standard et la bibliothèque runtime C. Toutefois, l’appel de setlocale modifie uniquement les paramètres régionaux de la bibliothèque runtime C ; la bibliothèque standard C++ n’est pas affectée.

Les exemples suivants montrent comment utiliser la fonction setlocale , la classe de paramètres régionaux et la fonction _configthreadlocale pour modifier les paramètres régionaux d’une application dans plusieurs scénarios différents.

Exemple : Modifier les paramètres régionaux avec les paramètres régionaux par thread activés

Dans cet exemple, le thread principal génère deux threads enfants. Le premier thread, thread A, active les paramètres régionaux par thread en appelant _configthreadlocale(_ENABLE_PER_THREAD_LOCALE). Le deuxième thread, thread B, ainsi que le thread principal, n’activent pas les paramètres régionaux par thread. Le thread A passe ensuite à la modification des paramètres régionaux à l’aide de la fonction setlocale de la bibliothèque runtime C.

Étant donné que les paramètres régionaux par thread sont activés, seules les fonctions de bibliothèque runtime C dans thread A commencent à utiliser les paramètres régionaux « français ». Les fonctions de bibliothèque runtime C dans thread B et dans le thread principal continuent d’utiliser les paramètres régionaux « C ». En outre, étant donné que setlocale n’affecte pas les paramètres régionaux de la bibliothèque standard C++, tous les objets de bibliothèque standard C++ continuent d’utiliser les paramètres régionaux « C ».

// multithread_locale_1.cpp
// compile with: /EHsc /MD
#include <clocale>
#include <cstdio>
#include <locale>
#include <process.h>
#include <windows.h>

#define NUM_THREADS 2
using namespace std;

unsigned __stdcall RunThreadA(void *params);
unsigned __stdcall RunThreadB(void *params);

BOOL localeSet = FALSE;
HANDLE printMutex = CreateMutex(NULL, FALSE, NULL);

int main()
{
    HANDLE threads[NUM_THREADS];

    unsigned aID;
    threads[0] = (HANDLE)_beginthreadex(
        NULL, 0, RunThreadA, NULL, 0, &aID);

    unsigned bID;
    threads[1] = (HANDLE)_beginthreadex(
        NULL, 0, RunThreadB, NULL, 0, &bID);

    WaitForMultipleObjects(2, threads, TRUE, INFINITE);

    printf_s("[Thread main] Per-thread locale is NOT enabled.\n");
    printf_s("[Thread main] CRT locale is set to \"%s\"\n",
        setlocale(LC_ALL, NULL));
    printf_s("[Thread main] locale::global is set to \"%s\"\n",
        locale().name().c_str());

    CloseHandle(threads[0]);
    CloseHandle(threads[1]);
    CloseHandle(printMutex);

    return 0;
}

unsigned __stdcall RunThreadA(void *params)
{
    _configthreadlocale(_ENABLE_PER_THREAD_LOCALE);
    setlocale(LC_ALL, "french");
    localeSet = TRUE;

    WaitForSingleObject(printMutex, INFINITE);
    printf_s("[Thread A] Per-thread locale is enabled.\n");
    printf_s("[Thread A] CRT locale is set to \"%s\"\n",
        setlocale(LC_ALL, NULL));
    printf_s("[Thread A] locale::global is set to \"%s\"\n\n",
        locale().name().c_str());
    ReleaseMutex(printMutex);

    return 1;
}

unsigned __stdcall RunThreadB(void *params)
{
    while (!localeSet)
        Sleep(100);

    WaitForSingleObject(printMutex, INFINITE);
    printf_s("[Thread B] Per-thread locale is NOT enabled.\n");
    printf_s("[Thread B] CRT locale is set to \"%s\"\n",
        setlocale(LC_ALL, NULL));
    printf_s("[Thread B] locale::global is set to \"%s\"\n\n",
        locale().name().c_str());
    ReleaseMutex(printMutex);

    return 1;
}
[Thread A] Per-thread locale is enabled.
[Thread A] CRT locale is set to "French_France.1252"
[Thread A] locale::global is set to "C"

[Thread B] Per-thread locale is NOT enabled.
[Thread B] CRT locale is set to "C"
[Thread B] locale::global is set to "C"

[Thread main] Per-thread locale is NOT enabled.
[Thread main] CRT locale is set to "C"
[Thread main] locale::global is set to "C"

Exemple : Modifier les paramètres régionaux globaux avec les paramètres régionaux par thread activés

Dans cet exemple, le thread principal génère deux threads enfants. Le premier thread, thread A, active les paramètres régionaux par thread en appelant _configthreadlocale(_ENABLE_PER_THREAD_LOCALE). Le deuxième thread, thread B, ainsi que le thread principal, n’activent pas les paramètres régionaux par thread. Le thread A passe ensuite à la modification des paramètres régionaux à l’aide de la méthode locale ::global de la bibliothèque standard C++.

Étant donné que les paramètres régionaux par thread sont activés, seules les fonctions de bibliothèque runtime C dans thread A commencent à utiliser les paramètres régionaux « français ». Les fonctions de bibliothèque runtime C dans thread B et dans le thread principal continuent d’utiliser les paramètres régionaux « C ». Toutefois, étant donné que la méthode locale ::global modifie les paramètres régionaux « globalement », tous les objets de bibliothèque standard C++ dans tous les threads commencent à utiliser les paramètres régionaux « français ».

// multithread_locale_2.cpp
// compile with: /EHsc /MD
#include <clocale>
#include <cstdio>
#include <locale>
#include <process.h>
#include <windows.h>

#define NUM_THREADS 2
using namespace std;

unsigned __stdcall RunThreadA(void *params);
unsigned __stdcall RunThreadB(void *params);

BOOL localeSet = FALSE;
HANDLE printMutex = CreateMutex(NULL, FALSE, NULL);

int main()
{
    HANDLE threads[NUM_THREADS];

    unsigned aID;
    threads[0] = (HANDLE)_beginthreadex(
        NULL, 0, RunThreadA, NULL, 0, &aID);

    unsigned bID;
    threads[1] = (HANDLE)_beginthreadex(
        NULL, 0, RunThreadB, NULL, 0, &bID);

    WaitForMultipleObjects(2, threads, TRUE, INFINITE);

    printf_s("[Thread main] Per-thread locale is NOT enabled.\n");
    printf_s("[Thread main] CRT locale is set to \"%s\"\n",
        setlocale(LC_ALL, NULL));
    printf_s("[Thread main] locale::global is set to \"%s\"\n",
        locale().name().c_str());

    CloseHandle(threads[0]);
    CloseHandle(threads[1]);
    CloseHandle(printMutex);

    return 0;
}

unsigned __stdcall RunThreadA(void *params)
{
    _configthreadlocale(_ENABLE_PER_THREAD_LOCALE);
    locale::global(locale("french"));
    localeSet = TRUE;

    WaitForSingleObject(printMutex, INFINITE);
    printf_s("[Thread A] Per-thread locale is enabled.\n");
    printf_s("[Thread A] CRT locale is set to \"%s\"\n",
        setlocale(LC_ALL, NULL));
    printf_s("[Thread A] locale::global is set to \"%s\"\n\n",
        locale().name().c_str());
    ReleaseMutex(printMutex);

    return 1;
}

unsigned __stdcall RunThreadB(void *params)
{
    while (!localeSet)
        Sleep(100);

    WaitForSingleObject(printMutex, INFINITE);
    printf_s("[Thread B] Per-thread locale is NOT enabled.\n");
    printf_s("[Thread B] CRT locale is set to \"%s\"\n",
        setlocale(LC_ALL, NULL));
    printf_s("[Thread B] locale::global is set to \"%s\"\n\n",
        locale().name().c_str());
    ReleaseMutex(printMutex);

    return 1;
}
[Thread A] Per-thread locale is enabled.
[Thread A] CRT locale is set to "French_France.1252"
[Thread A] locale::global is set to "French_France.1252"

[Thread B] Per-thread locale is NOT enabled.
[Thread B] CRT locale is set to "C"
[Thread B] locale::global is set to "French_France.1252"

[Thread main] Per-thread locale is NOT enabled.
[Thread main] CRT locale is set to "C"
[Thread main] locale::global is set to "French_France.1252"

Exemple : Modifier les paramètres régionaux sans paramètres régionaux par thread activé

Dans cet exemple, le thread principal génère deux threads enfants. Le premier thread, thread A, active les paramètres régionaux par thread en appelant _configthreadlocale(_ENABLE_PER_THREAD_LOCALE). Le deuxième thread, thread B, ainsi que le thread principal, n’activent pas les paramètres régionaux par thread. Le thread B passe ensuite à la modification des paramètres régionaux à l’aide de la fonction setlocale de la bibliothèque runtime C.

Étant donné que le thread B n’a pas de paramètres régionaux par thread activé, les fonctions de bibliothèque runtime C dans le thread B et dans le thread principal commencent à utiliser les paramètres régionaux « français ». Les fonctions de bibliothèque runtime C dans thread A continuent d’utiliser les paramètres régionaux « C », car les paramètres régionaux du thread A sont activés par thread. En outre, étant donné que setlocale n’affecte pas les paramètres régionaux de la bibliothèque standard C++, tous les objets de bibliothèque standard C++ continuent d’utiliser les paramètres régionaux « C ».

// multithread_locale_3.cpp
// compile with: /EHsc /MD
#include <clocale>
#include <cstdio>
#include <locale>
#include <process.h>
#include <windows.h>

#define NUM_THREADS 2
using namespace std;

unsigned __stdcall RunThreadA(void *params);
unsigned __stdcall RunThreadB(void *params);

BOOL localeSet = FALSE;
BOOL configThreadLocaleCalled = FALSE;
HANDLE printMutex = CreateMutex(NULL, FALSE, NULL);

int main()
{
    HANDLE threads[NUM_THREADS];

    unsigned aID;
    threads[0] = (HANDLE)_beginthreadex(
        NULL, 0, RunThreadA, NULL, 0, &aID);

    unsigned bID;
    threads[1] = (HANDLE)_beginthreadex(
        NULL, 0, RunThreadB, NULL, 0, &bID);

    WaitForMultipleObjects(2, threads, TRUE, INFINITE);

    printf_s("[Thread main] Per-thread locale is NOT enabled.\n");
    printf_s("[Thread main] CRT locale is set to \"%s\"\n",
        setlocale(LC_ALL, NULL));
    printf_s("[Thread main] locale::global is set to \"%s\"\n",
        locale().name().c_str());

    CloseHandle(threads[0]);
    CloseHandle(threads[1]);
    CloseHandle(printMutex);

    return 0;
}

unsigned __stdcall RunThreadA(void *params)
{
    _configthreadlocale(_ENABLE_PER_THREAD_LOCALE);
    configThreadLocaleCalled = TRUE;
    while (!localeSet)
        Sleep(100);

    WaitForSingleObject(printMutex, INFINITE);
    printf_s("[Thread A] Per-thread locale is enabled.\n");
    printf_s("[Thread A] CRT locale is set to \"%s\"\n",
        setlocale(LC_ALL, NULL));
    printf_s("[Thread A] locale::global is set to \"%s\"\n\n",
        locale().name().c_str());
    ReleaseMutex(printMutex);

    return 1;
}

unsigned __stdcall RunThreadB(void *params)
{
    while (!configThreadLocaleCalled)
        Sleep(100);
    setlocale(LC_ALL, "french");
    localeSet = TRUE;

    WaitForSingleObject(printMutex, INFINITE);
    printf_s("[Thread B] Per-thread locale is NOT enabled.\n");
    printf_s("[Thread B] CRT locale is set to \"%s\"\n",
        setlocale(LC_ALL, NULL));
    printf_s("[Thread B] locale::global is set to \"%s\"\n\n",
        locale().name().c_str());
    ReleaseMutex(printMutex);

    return 1;
}
[Thread B] Per-thread locale is NOT enabled.
[Thread B] CRT locale is set to "French_France.1252"
[Thread B] locale::global is set to "C"

[Thread A] Per-thread locale is enabled.
[Thread A] CRT locale is set to "C"
[Thread A] locale::global is set to "C"

[Thread main] Per-thread locale is NOT enabled.
[Thread main] CRT locale is set to "French_France.1252"
[Thread main] locale::global is set to "C"

Exemple : Modifier les paramètres régionaux globaux sans paramètres régionaux par thread activés

Dans cet exemple, le thread principal génère deux threads enfants. Le premier thread, thread A, active les paramètres régionaux par thread en appelant _configthreadlocale(_ENABLE_PER_THREAD_LOCALE). Le deuxième thread, thread B, ainsi que le thread principal, n’activent pas les paramètres régionaux par thread. Le thread B passe ensuite à la modification des paramètres régionaux à l’aide de la méthode locale ::global de la bibliothèque standard C++.

Étant donné que le thread B n’a pas de paramètres régionaux par thread activé, les fonctions de bibliothèque runtime C dans le thread B et dans le thread principal commencent à utiliser les paramètres régionaux « français ». Les fonctions de bibliothèque runtime C dans thread A continuent d’utiliser les paramètres régionaux « C », car les paramètres régionaux du thread A sont activés par thread. Toutefois, étant donné que la méthode locale ::global modifie les paramètres régionaux « globalement », tous les objets de bibliothèque standard C++ dans tous les threads commencent à utiliser les paramètres régionaux « français ».

// multithread_locale_4.cpp
// compile with: /EHsc /MD
#include <clocale>
#include <cstdio>
#include <locale>
#include <process.h>
#include <windows.h>

#define NUM_THREADS 2
using namespace std;

unsigned __stdcall RunThreadA(void *params);
unsigned __stdcall RunThreadB(void *params);

BOOL localeSet = FALSE;
BOOL configThreadLocaleCalled = FALSE;
HANDLE printMutex = CreateMutex(NULL, FALSE, NULL);

int main()
{
    HANDLE threads[NUM_THREADS];

    unsigned aID;
    threads[0] = (HANDLE)_beginthreadex(
        NULL, 0, RunThreadA, NULL, 0, &aID);

    unsigned bID;
    threads[1] = (HANDLE)_beginthreadex(
        NULL, 0, RunThreadB, NULL, 0, &bID);

    WaitForMultipleObjects(2, threads, TRUE, INFINITE);

    printf_s("[Thread main] Per-thread locale is NOT enabled.\n");
    printf_s("[Thread main] CRT locale is set to \"%s\"\n",
        setlocale(LC_ALL, NULL));
    printf_s("[Thread main] locale::global is set to \"%s\"\n",
        locale().name().c_str());

    CloseHandle(threads[0]);
    CloseHandle(threads[1]);
    CloseHandle(printMutex);

    return 0;
}

unsigned __stdcall RunThreadA(void *params)
{
    _configthreadlocale(_ENABLE_PER_THREAD_LOCALE);
    configThreadLocaleCalled = TRUE;
    while (!localeSet)
        Sleep(100);

    WaitForSingleObject(printMutex, INFINITE);
    printf_s("[Thread A] Per-thread locale is enabled.\n");
    printf_s("[Thread A] CRT locale is set to \"%s\"\n",
        setlocale(LC_ALL, NULL));
    printf_s("[Thread A] locale::global is set to \"%s\"\n\n",
        locale().name().c_str());
    ReleaseMutex(printMutex);

    return 1;
}

unsigned __stdcall RunThreadB(void *params)
{
    while (!configThreadLocaleCalled)
        Sleep(100);
    locale::global(locale("french"));
    localeSet = TRUE;

    WaitForSingleObject(printMutex, INFINITE);
    printf_s("[Thread B] Per-thread locale is NOT enabled.\n");
    printf_s("[Thread B] CRT locale is set to \"%s\"\n",
        setlocale(LC_ALL, NULL));
    printf_s("[Thread B] locale::global is set to \"%s\"\n\n",
        locale().name().c_str());
    ReleaseMutex(printMutex);

    return 1;
}
[Thread B] Per-thread locale is NOT enabled.
[Thread B] CRT locale is set to "French_France.1252"
[Thread B] locale::global is set to "French_France.1252"

[Thread A] Per-thread locale is enabled.
[Thread A] CRT locale is set to "C"
[Thread A] locale::global is set to "French_France.1252"

[Thread main] Per-thread locale is NOT enabled.
[Thread main] CRT locale is set to "French_France.1252"
[Thread main] locale::global is set to "French_France.1252"

Voir aussi

Prise en charge du multithreading pour le code plus ancien (Visual C++)
_beginthread, _beginthreadex
_configthreadlocale
setlocale
Internationalisation
Paramètres régionaux
<clocale>
<paramètres régionaux>
locale, classe