Sdílet prostřednictvím


Multithreading a národní prostředí

Knihovna modulu runtime jazyka C i standardní knihovna jazyka C++ poskytují podporu pro změnu národního prostředí programu. Toto téma popisuje problémy, ke kterým dochází při použití funkcí národního prostředí obou knihoven ve vícevláknové aplikaci.

Poznámky

Pomocí knihovny modulu runtime jazyka C můžete vytvářet vícevláknové aplikace pomocí funkcí _beginthread a _beginthreadex funkcí. Toto téma se zabývá pouze vícevláknovými aplikacemi vytvořenými pomocí těchto funkcí. Další informace najdete v tématu _beginthread _beginthreadex.

Chcete-li změnit národní prostředí pomocí knihovny modulu runtime jazyka C, použijte funkci setlocale . V předchozích verzích visual C++ by tato funkce vždy upravovala národní prostředí v celé aplikaci. Nyní je podporováno nastavení národního prostředí pro jednotlivá vlákna. To se provádí pomocí funkce _configthreadlocale . Chcete-li určit, že setlocale by měl změnit pouze národní prostředí v aktuálním vlákně, volání _configthreadlocale(_ENABLE_PER_THREAD_LOCALE) v daném vlákně. Volání naopak způsobí, _configthreadlocale(_DISABLE_PER_THREAD_LOCALE) že vlákno použije globální národní prostředí a jakékoli volání setlocale v daném vlákně změní národní prostředí ve všech vláknech, která nejsou explicitně povolena pro každé vlákno národního prostředí.

Chcete-li změnit národní prostředí pomocí knihovny modulu runtime jazyka C++, použijte třídu národního prostředí. Voláním metody locale::global změníte národní prostředí v každém vlákně, které explicitně nepovoluje národní prostředí pro každé vlákno. Chcete-li změnit národní prostředí v jednom vlákně nebo části aplikace, jednoduše vytvořte instanci locale objektu v tomto vlákně nebo části kódu.

Poznámka:

Volání národního prostředí::global změní národní prostředí pro standardní knihovnu C++ i knihovnu modulu runtime jazyka C++. Volání setlocale však změní národní prostředí pouze pro knihovnu modulu runtime jazyka C; standardní knihovna jazyka C++ není ovlivněna.

Následující příklady ukazují, jak použít funkci setlocale , třídu národního prostředí a funkci _configthreadlocale ke změně národního prostředí aplikace v několika různých scénářích.

Příklad: Změna národního prostředí s povoleným národním prostředím pro jednotlivá vlákna

V tomto příkladu hlavní vlákno vytvoří dvě podřízená vlákna. První vlákno, vlákno A, umožňuje národní prostředí pro jednotlivá vlákna voláním _configthreadlocale(_ENABLE_PER_THREAD_LOCALE). Druhé vlákno, vlákno B a hlavní vlákno, nepovoluje národní prostředí pro jednotlivá vlákna. Vlákno A pak pokračuje změnou národního prostředí pomocí funkce setlocale knihovny modulu runtime jazyka C.

Vzhledem k tomu, že je povolené národní prostředí pro vlákno A, začnou používat "francouzské" národní prostředí pouze funkce knihovny modulu runtime C ve vlákně A. Funkce knihovny modulu runtime jazyka C ve vlákně B a v hlavním vlákně nadále používají národní prostředí "C". Vzhledem k tomu, že setlocale nemá vliv na národní prostředí standardní knihovny C++, všechny objekty standardní knihovny jazyka C++ nadále používají národní prostředí "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"

Příklad: Změna globálního národního prostředí s povoleným národním prostředím pro jednotlivá vlákna

V tomto příkladu hlavní vlákno vytvoří dvě podřízená vlákna. První vlákno, vlákno A, umožňuje národní prostředí pro jednotlivá vlákna voláním _configthreadlocale(_ENABLE_PER_THREAD_LOCALE). Druhé vlákno, vlákno B a hlavní vlákno, nepovoluje národní prostředí pro jednotlivá vlákna. Vlákno A pak pokračuje ve změně národního prostředí pomocí metody locale::global standardní knihovny jazyka C++.

Vzhledem k tomu, že je povolené národní prostředí pro vlákno A, začnou používat "francouzské" národní prostředí pouze funkce knihovny modulu runtime C ve vlákně A. Funkce knihovny modulu runtime jazyka C ve vlákně B a v hlavním vlákně nadále používají národní prostředí "C". Vzhledem k tomu, že národní prostředí::global změní národní prostředí "globálně", všechny objekty standardní knihovny C++ ve všech vláknech začnou používat "francouzské" národní prostředí.

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

Příklad: Změna národního prostředí bez povoleného národního prostředí pro jednotlivá vlákna

V tomto příkladu hlavní vlákno vytvoří dvě podřízená vlákna. První vlákno, vlákno A, umožňuje národní prostředí pro jednotlivá vlákna voláním _configthreadlocale(_ENABLE_PER_THREAD_LOCALE). Druhé vlákno, vlákno B a hlavní vlákno, nepovoluje národní prostředí pro jednotlivá vlákna. Vlákno B pak pokračuje ve změně národního prostředí pomocí funkce setlocale knihovny modulu runtime jazyka C.

Vzhledem k tomu, že vlákno B nemá povolené národní prostředí pro jednotlivé vlákna, funkce knihovny modulu runtime jazyka C ve vlákně B a v hlavním vlákně začínají používat "francouzské" národní prostředí. Funkce knihovny modulu runtime jazyka C ve vlákně A nadále používají národní prostředí "C", protože je povolené národní prostředí vlákna A pro každé vlákno. Vzhledem k tomu, že setlocale nemá vliv na národní prostředí standardní knihovny C++, všechny objekty standardní knihovny jazyka C++ nadále používají národní prostředí "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"

Příklad: Změna globálního národního prostředí bez povoleného národního prostředí pro jednotlivá vlákna

V tomto příkladu hlavní vlákno vytvoří dvě podřízená vlákna. První vlákno, vlákno A, umožňuje národní prostředí pro jednotlivá vlákna voláním _configthreadlocale(_ENABLE_PER_THREAD_LOCALE). Druhé vlákno, vlákno B a hlavní vlákno, nepovoluje národní prostředí pro jednotlivá vlákna. Vlákno B pak pokračuje ve změně národního prostředí pomocí metody locale::global standardní knihovny jazyka C++.

Vzhledem k tomu, že vlákno B nemá povolené národní prostředí pro jednotlivé vlákna, funkce knihovny modulu runtime jazyka C ve vlákně B a v hlavním vlákně začínají používat "francouzské" národní prostředí. Funkce knihovny modulu runtime jazyka C ve vlákně A nadále používají národní prostředí "C", protože je povolené národní prostředí vlákna A pro každé vlákno. Vzhledem k tomu, že národní prostředí::global změní národní prostředí "globálně", všechny objekty standardní knihovny C++ ve všech vláknech začnou používat "francouzské" národní prostředí.

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

Viz také

Podpora multithreadingu ve starším kódu (Visual C++)
_beginthread, _beginthreadex
_configthreadlocale
setlocale
Internacionalizace
Národní prostředí
<clocale>
<locale>
locale – třída