Sdílet prostřednictvím


Multithreading a národní prostředí

Běhová knihovna jazyka C a standartní knihovna jazyka C++ poskytují podporu pro změny národního prostředí Vašeho programu.Toto téma popisuje problémy, které vznikají při použití funkce národního prostředí obou knihoven ve více vláknové aplikaci.

Poznámky

S běhovou knihovnou jazyka C můžete vytvořit více vláknové aplikace, za použití funkcí _beginthread a _beginthreadex. Toto téma pokrývá pouze více vláknové aplikace, vytvořené pomocí těchto funkcí.Další informace naleznete v tématu _beginthread _beginthreadex vrací.

Chcete-li změnit národní prostředí pomocí běhové knihovny jazyka C, použijte funkci setlocale. V předchozích verzích Visual C++, by měla vždy tato funkce změnit národní prostředí v rámci celé aplikace. Nyní je zde podpora pro nastavení národního prostředí na základě vlákna.To se provádí pomocí funkce _configthreadlocale. Chcete-li určit setlocale, by mělo pouze změnit národní prostředí v aktuálním vlákně, volání _configthreadlocale(_ENABLE_PER_THREAD_LOCALE) v tomto vlákně. Naopak volání _configthreadlocale(_DISABLE_PER_THREAD_LOCALE) způsobí, že toto vlákno použije globální národní prostředí a jakékoliv volání setlocale v tomto vlákně může změnit národní prostředí ve všech vláknech, které nemají explicitní povolení národního prostředí pro vlákno.

Chcete-li změnit národní prostředí pomocí běhové knihovny jazyka C, použijte funkci locale Class. Voláním metody locale::global, změníte národní prostředí v každém vlákně, které nemá explicitní povolení národního prostředí pro vlákno. Chcete-li změnit národní prostředí v jediném vlákně nebo v části aplikace, jednoduše vytvořite instanci objektu locale v daném vlákně nebo části kódu.

[!POZNÁMKA]

Volání locale::global změní národní prostředí pro standartní knihovnu jazyka C++ a pro běhovou knihovnu jazyka C. Avšak volání setlocale změní pouze národní prostředí pro běhovou knihovnu jazyka C; Standartní knihovna jazyka C++ není ohrožena.

Následující příklady ukazují, jak používat funkci setlocale, locale Classa funkci _configthreadlocale, chcete-li změnit národní prostředí aplikace v několika různých scénářích.

Příklad

V tomto příkladu vytvoří hlavní vlákno dva potomky.První vlákno, Thread A, povoluje národní prostředí pro vlákno, voláním _configthreadlocale(_ENABLE_PER_THREAD_LOCALE). Druhé vlákno, Thread B, tak jako hlavní vlákno, nepovoluje národní prostředí pro vlákno.Vlákno Thread A poté provede změny národního prostředí, použitím funkce setlocale běhové knihovny jazyka C.

Jakmile má vlákno Thread A povoleno národní prostředí pro vlákno, začínají pouze funkce běhové knihovny jazyka C ve vlákně Thread A používat "Francouzské" prostředí.Funkce běhové knihovny jazyka C ve vlákně Thread B a v hlavním vlákně, používají nadále národní prostředí jazyka C.Navíc jakmile setlocale neovlivní národní prostředí standartní knihovny jazyka C++, všechny objekty standartní knihovny jazyka C používají nadále národní prostředí jazyka 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;
}
  
  
  
  

V tomto příkladu vytvoří hlavní vlákno dva potomky.První vlákno, Thread A, povoluje národní prostředí pro vlákno, voláním _configthreadlocale(_ENABLE_PER_THREAD_LOCALE). Druhé vlákno, Thread B, tak jako hlavní vlákno, nepovoluje národní prostředí pro vlákno.Vlákno Thread A poté provede změny národního prostředí, použitím metody locale::global standartní knihovny jazyka C++.

Jakmile má vlákno Thread A povoleno národní prostředí pro vlákno, začínají pouze funkce běhové knihovny jazyka C ve vlákně Thread A používat "Francouzské" prostředí.Funkce běhové knihovny jazyka C ve vlákně Thread B a v hlavním vlákně, používají nadále národní prostředí jazyka C.Avšak jakmile metoda locale::global změní "globální" národní prostředí, všechny objekty standartní knihovny jazyka 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;
}
  
  
  
  

V tomto příkladu vytvoří hlavní vlákno dva potomky.První vlákno, Thread A, povoluje národní prostředí pro vlákno, voláním _configthreadlocale(_ENABLE_PER_THREAD_LOCALE). Druhé vlákno, Thread B, tak jako hlavní vlákno, nepovoluje národní prostředí pro vlákno.Vlákno Thread B poté provede změny národního prostředí, použitím funkce setlocale běhové knihovny jazyka C.

Jakmile vlákno Thread B nemá povoleno národní prostředí pro vlákno, začnou používat funkce běhové knihovny jazyka C ve vlákně Thread B a v hlavním vlákně "Francouzské" národní prostředí.Funkce běhové knihovny jazyka C ve vlákně Thread A nadále používají národní prostředí jazyka C, protože vlákno Thread A má povoleno národní prostředí pro vlákno.Navíc jakmile setlocale neovlivní národní prostředí standartní knihovny jazyka C++, všechny objekty standartní knihovny jazyka C používají nadále národní prostředí jazyka 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;
}
  
  
  
  

V tomto příkladu vytvoří hlavní vlákno dva potomky.První vlákno, Thread A, povoluje národní prostředí pro vlákno, voláním _configthreadlocale(_ENABLE_PER_THREAD_LOCALE). Druhé vlákno, Thread B, tak jako hlavní vlákno, nepovoluje národní prostředí pro vlákno.Vlákno Thread B poté provede změny národního prostředí, použitím metody locale::global standartní knihovny jazyka C++.

Jakmile vlákno Thread B nemá povoleno národní prostředí pro vlákno, začnou používat funkce běhové knihovny jazyka C ve vlákně Thread B a v hlavním vlákně "Francouzské" národní prostředí.Funkce běhové knihovny jazyka C ve vlákně Thread A nadále používají národní prostředí jazyka C, protože vlákno Thread A má povoleno národní prostředí pro vlákno.Avšak jakmile metoda locale::global změní "globální" národní prostředí, všechny objekty standartní knihovny jazyka 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;
}
  
  
  
  

Viz také

Referenční dokumentace

_beginthread _beginthreadex vrací

_configthreadlocale

setlocale

Internacionalizace

Národní prostředí

<clocale>

<locale>

locale Class

Koncepty

Multithreading podpora pro starší kód (Visual C++)