Freigeben über


Multithreading und Gebietsschemas

Sowohl die C Runtime Library als auch die C++ Standard Library bieten Unterstützung für die Änderung des Gebietsschemas Ihres Programms. In diesem Thema werden Probleme erörtert, die bei der Verwendung der Locale-Funktionen beider Bibliotheken in einer Multithreading-Anwendung auftreten.

Hinweise

Mit der C Runtime Library können Sie mit den Funktionen _beginthread und _beginthreadex Multithreading-Anwendungen erstellen. Dieses Thema behandelt nur Multithreading-Anwendungen, die mit diesen Funktionen erstellt wurden. Weitere Informationen finden Sie unter _beginthread, _beginthreadex.

Um das Gebietsschema mit Hilfe der C Runtime Library zu ändern, verwenden Sie die Funktion setlocale. In früheren Versionen von Visual C++ änderte diese Funktion immer das Gebietsschema der gesamten Anwendung. Jetzt ist es möglich, das Gebietsschema für jeden einzelnen Thread einzustellen. Dafür wird die _configthreadlocale-Funktion genutzt. Um festzulegen, dass setlocale das Gebiet nur im aktuellen Thread ändern soll, rufen Sie _configthreadlocale(_ENABLE_PER_THREAD_LOCALE) in diesem Thread auf. Umgekehrt führt der Aufruf von _configthreadlocale(_DISABLE_PER_THREAD_LOCALE) dazu, dass dieser Thread das globale Gebietsschema verwendet, und jede Anfrage an setlocale in diesem Thread ändert das Gebietsschema in allen Threads, die das Gebietsschema pro Thread nicht explizit aktiviert haben.

Um das Gebietsschema mit Hilfe der C++ Runtime Library zu ändern, verwenden Sie die Gebietsschema-Klasse. Indem Sie die Methode locale::global anfragen, ändern Sie das Gebietsschema in jedem Thread, der das Gebietsschema pro Thread nicht explizit aktiviert hat. Um das Gebietsschema in einem einzelnen Thread oder Teil einer Anwendung zu ändern, erstellen Sie einfach eine Instanz eines locale-Objekts in diesem Thread oder Teil des Codes.

Hinweis

Der Aufruf von locale::global ändert die Locale sowohl für die C++ Standardbibliothek als auch für die C Runtime Library. Die Anfrage setlocale ändert jedoch nur das Gebietsschema für die C Runtime Library; die C++ Standard Library ist davon nicht betroffen.

Die folgenden Beispiele zeigen, wie Sie mit der Funktion setlocale, der Gebietsschema-Klasse und der Funktion _configthreadlocale vorgehen, um das Gebietsschema einer Anwendung in mehreren verschiedenen Szenarien zu ändern.

Beispiel: Ändern des Gebietsschemas bei aktiviertem Gebietsschema pro Thread

In diesem Beispiel legt der Haupt-Thread zwei untergeordnete Threads an. Der erste Thread, Thread A, aktiviert die Lokalisierung pro Thread durch den Aufruf von _configthreadlocale(_ENABLE_PER_THREAD_LOCALE). Der zweite Thread, Thread B, sowie der Haupt-Thread, aktivieren nicht die Ortsbestimmung pro Thread. Thread A ändert daraufhin das Gebietsschema mit der Funktion setlocale der C Runtime Library.

Da in Thread A das Gebietsschema pro Thread aktiviert ist, verwenden nur die Funktionen der C-Laufzeitbibliothek in Thread A das Gebietsschema „französisch“. Die Funktionen der C Runtime Library in Thread B und im Hauptthread verwenden weiterhin das Gebietsschema „C“. Da setlocale das Gebietsschema der C++ Standardbibliothek nicht beeinflusst, verwenden alle Objekte der C++ Standardbibliothek weiterhin das Gebietsschema „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"

Beispiel: Globales Gebietsschema ändern mit aktiviertem Gebietsschema pro Thread

In diesem Beispiel legt der Haupt-Thread zwei untergeordnete Threads an. Der erste Thread, Thread A, aktiviert die Lokalisierung pro Thread durch den Aufruf von _configthreadlocale(_ENABLE_PER_THREAD_LOCALE). Der zweite Thread, Thread B, sowie der Haupt-Thread, aktivieren nicht die Ortsbestimmung pro Thread. Thread A ändert dann das Gebietsschema mit der Methode locale::global der C++ Standardbibliothek.

Da in Thread A das Gebietsschema pro Thread aktiviert ist, verwenden nur die Funktionen der C-Laufzeitbibliothek in Thread A das Gebietsschema „französisch“. Die Funktionen der C Runtime Library in Thread B und im Hauptthread verwenden weiterhin das Gebietsschema „C“. Da die locale::global-Methode das Gebietsschema jedoch „global“ ändert, verwenden alle Objekte der C++ Standardbibliothek in allen Threads das „französische“ Gebietsschema.

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

Beispiel: Gebietsschema ändern, ohne dass das Gebietsschema pro Thread aktiviert ist

In diesem Beispiel legt der Haupt-Thread zwei untergeordnete Threads an. Der erste Thread, Thread A, aktiviert die Lokalisierung pro Thread durch den Aufruf von _configthreadlocale(_ENABLE_PER_THREAD_LOCALE). Der zweite Thread, Thread B, sowie der Haupt-Thread, aktivieren nicht die Ortsbestimmung pro Thread. Thread B ändert dann das Gebietsschema mit der Funktion setlocale der C Runtime Library.

Da in Thread B kein Gebietsschema pro Thread aktiviert ist, verwenden die Funktionen der C- Runtime Library in Thread B und im Hauptthread zunächst das Gebietsschema „französisch“. Die Funktionen der C- Runtime Library in Thread A verwenden weiterhin das Gebietsschema „C“, da in Thread A das Gebietsschema pro Thread aktiviert ist. Da setlocale das Gebietsschema der C++ Standardbibliothek nicht beeinflusst, verwenden alle Objekte der C++ Standardbibliothek weiterhin das Gebietsschema „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"

Beispiel: Globales Gebietsschema ändern, ohne dass das Gebietsschema pro Thread aktiviert ist

In diesem Beispiel legt der Haupt-Thread zwei untergeordnete Threads an. Der erste Thread, Thread A, aktiviert die Lokalisierung pro Thread durch den Aufruf von _configthreadlocale(_ENABLE_PER_THREAD_LOCALE). Der zweite Thread, Thread B, sowie der Haupt-Thread, aktivieren nicht die Ortsbestimmung pro Thread. Thread B ändert dann das Gebietsschema mit der Methode locale::global der C++ Standardbibliothek.

Da in Thread B kein Gebietsschema pro Thread aktiviert ist, verwenden die Funktionen der C- Runtime Library in Thread B und im Hauptthread zunächst das Gebietsschema „französisch“. Die Funktionen der C- Runtime Library in Thread A verwenden weiterhin das Gebietsschema „C“, da in Thread A das Gebietsschema pro Thread aktiviert ist. Da die locale::global-Methode das Gebietsschema jedoch „global“ ändert, verwenden alle Objekte der C++ Standardbibliothek in allen Threads das „französische“ Gebietsschema.

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

Weitere Informationen

Multithreadingunterstützung für älteren Code (Visual C++)
_beginthread, _beginthreadex
_configthreadlocale
setlocale
Internationalisierung
Gebietsschema
<Clocale>
<Gebietsschema>
Gebietsschema-Klasse