Delen via


Multithreading en lokalisaties

Zowel de C Runtime-bibliotheek als de C++-standaardbibliotheek bieden ondersteuning voor het wijzigen van de landinstelling van uw programma. In dit onderwerp worden problemen besproken die zich voordoen bij het gebruik van de landinstellingen van beide bibliotheken in een multithreaded-toepassing.

Opmerkingen

Met de C Runtime-bibliotheek kunt u multithreaded toepassingen maken met behulp van de _beginthread en _beginthreadex functies. In dit onderwerp worden alleen meerdraadstoepassingen behandeld die zijn gemaakt met behulp van deze functies. Zie _beginthread, _beginthreadex voor meer informatie.

Als u de landinstelling wilt wijzigen met behulp van de C Runtime-bibliotheek, gebruikt u de setlocale-functie . In eerdere versies van Visual C++ zou deze functie altijd de landinstelling in de hele toepassing wijzigen. Er is nu ondersteuning voor het instellen van de locatie-instelling per afzonderlijke thread. Dit gebeurt met behulp van de functie _configthreadlocale . Als u wilt opgeven dat setlocale alleen de landinstelling in de huidige thread moet wijzigen, roept _configthreadlocale(_ENABLE_PER_THREAD_LOCALE) u die thread aan. Omgekeerd zorgt het aanroepen _configthreadlocale(_DISABLE_PER_THREAD_LOCALE) ervoor dat die thread gebruikmaakt van de globale landinstelling en dat elke aanroep om setlocale in die thread in te stellen de landinstelling wijzigt in alle threads die niet expliciet per thread-landinstelling zijn ingeschakeld.

Als u de landinstelling wilt wijzigen met behulp van de C++-runtimebibliotheek, gebruikt u de landinstellingsklasse. Door de locale::global methode aan te roepen, wijzigt u de locale in elke thread die niet expliciet een per-thread locale heeft ingeschakeld. Als u de landinstelling in één thread of gedeelte van een toepassing wilt wijzigen, maakt u gewoon een exemplaar van een locale object in die thread of een deel van de code.

Opmerking

Landinstellingen aanroepen::global wijzigt de landinstelling voor zowel de standaardbibliotheek van C++ als de C Runtime-bibliotheek. Het aanroepen van setlocale wijzigt echter alleen de landinstelling voor de C Runtime-bibliotheek; De C++-standaardbibliotheek wordt niet beïnvloed.

In de volgende voorbeelden ziet u hoe u de setlocale-functie , de landinstellingsklasse en de _configthreadlocale-functie gebruikt om de landinstelling van een toepassing in verschillende scenario's te wijzigen.

Voorbeeld: Locale wijzigen met per-thread locale ingeschakeld

In dit voorbeeld spawnt de hoofdthread twee kindthreads. De eerste thread, Thread A, maakt landinstellingen per thread mogelijk door aan te roepen _configthreadlocale(_ENABLE_PER_THREAD_LOCALE). De tweede thread, thread B en de hoofdthread, schakelt de landinstelling per thread niet in. Thread A gaat vervolgens verder met het wijzigen van de landinstelling met behulp van de setlocale-functie van de C Runtime-bibliotheek.

Omdat Thread A landinstellingen per thread heeft ingeschakeld, beginnen alleen de C Runtime-bibliotheekfuncties in Thread A de landinstelling 'frans' te gebruiken. De C Runtime-bibliotheekfuncties in Thread B en in de hoofdthread blijven de landinstelling 'C' gebruiken. Omdat setlocale geen invloed heeft op de landinstelling van de standaardbibliotheek van C++ blijven alle standaardbibliotheekobjecten van C++ de landinstelling C++ gebruiken.

// 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"

Voorbeeld: Globale landinstelling wijzigen met landinstellingen per thread ingeschakeld

In dit voorbeeld spawnt de hoofdthread twee kindthreads. De eerste thread, Thread A, maakt landinstellingen per thread mogelijk door aan te roepen _configthreadlocale(_ENABLE_PER_THREAD_LOCALE). De tweede thread, thread B en de hoofdthread, schakelt de landinstelling per thread niet in. Thread A gaat vervolgens verder met het wijzigen van de landinstelling met behulp van de landinstelling::globale methode van de C++-standaardbibliotheek.

Omdat Thread A landinstellingen per thread heeft ingeschakeld, beginnen alleen de C Runtime-bibliotheekfuncties in Thread A de landinstelling 'frans' te gebruiken. De C Runtime-bibliotheekfuncties in Thread B en in de hoofdthread blijven de landinstelling 'C' gebruiken. Aangezien de landinstelling::global-methode echter de landinstelling 'globaal' wijzigt, gaan alle standaardbibliotheekobjecten van C++ in alle threads de landinstelling 'frans' gebruiken.

// 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"

Voorbeeld: Taalinstelling wijzigen zonder per-thread taalinstelling ingeschakeld.

In dit voorbeeld spawnt de hoofdthread twee kindthreads. De eerste thread, Thread A, maakt landinstellingen per thread mogelijk door aan te roepen _configthreadlocale(_ENABLE_PER_THREAD_LOCALE). De tweede thread, thread B en de hoofdthread, schakelt de landinstelling per thread niet in. Thread B gaat vervolgens verder met het wijzigen van de landinstelling met behulp van de setlocale-functie van de C Runtime-bibliotheek.

Omdat thread B geen landinstelling per thread heeft ingeschakeld, gebruiken de C Runtime-bibliotheekfuncties in thread B en in de hoofddraad de landinstelling 'frans'. De C Runtime Library-functies in Thread A blijven de landinstelling 'C' gebruiken omdat thread A landinstellingen per thread heeft ingeschakeld. Omdat setlocale geen invloed heeft op de landinstelling van de standaardbibliotheek van C++ blijven alle standaardbibliotheekobjecten van C++ de landinstelling C++ gebruiken.

// 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"

Voorbeeld: Globale landinstellingen wijzigen waarbij lokale instellingen per draad niet zijn ingeschakeld

In dit voorbeeld spawnt de hoofdthread twee kindthreads. De eerste thread, Thread A, maakt landinstellingen per thread mogelijk door aan te roepen _configthreadlocale(_ENABLE_PER_THREAD_LOCALE). De tweede thread, thread B en de hoofdthread, schakelt de landinstelling per thread niet in. Thread B gaat vervolgens verder met het wijzigen van de landinstelling met behulp van de landinstelling::globale methode van de C++-standaardbibliotheek.

Omdat thread B geen landinstelling per thread heeft ingeschakeld, gebruiken de C Runtime-bibliotheekfuncties in thread B en in de hoofddraad de landinstelling 'frans'. De C Runtime Library-functies in Thread A blijven de landinstelling 'C' gebruiken omdat thread A landinstellingen per thread heeft ingeschakeld. Aangezien de landinstelling::global-methode echter de landinstelling 'globaal' wijzigt, gaan alle standaardbibliotheekobjecten van C++ in alle threads de landinstelling 'frans' gebruiken.

// 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"

Zie ook

Ondersteuning voor multithreading voor oudere code (Visual C++)
_beginthread, _beginthreadex
_configthreadlocale
setlocale
Internationalisering
Lokale instellingen
<clocale>
<oord>
localeklasse