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.
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 – třída. 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řte 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 – třídaa 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;
}