多執行緒和地區設定
C 執行時間連結庫和C++標準連結庫都支援變更程式的地區設定。 本主題討論在多線程應用程式中使用這兩個連結庫的地區設定功能時所發生的問題。
備註
使用 C 執行時間連結庫,您可以使用 和 _beginthreadex
函式來建立多線程應用程式_beginthread
。 本主題僅涵蓋使用這些函式所建立的多線程應用程式。 如需詳細資訊,請參閱 _beginthread、_beginthreadex。
若要使用 C 執行時間連結庫變更地區設定,請使用 setlocale 函式。 在舊版的 Visual C++中,此函式一律會在整個應用程式中修改地區設定。 現在支援以每個線程為基礎設定地區設定。 這是使用 _configthreadlocale 函式完成的。 若要指定 setlocale 應該只變更目前線程中的地區設定,請在該線程中呼叫 _configthreadlocale(_ENABLE_PER_THREAD_LOCALE)
。 相反地,呼叫_configthreadlocale(_DISABLE_PER_THREAD_LOCALE)
會導致該線程使用全域地區設定,而該線程中任何 setlocale 的呼叫都會變更尚未明確啟用每個線程地區設定的所有線程的地區設定。
若要使用 C++ Runtime Library 變更地區設定,請使用 地區設定類別。 藉由呼叫 locale::global 方法,您可以在未明確啟用每個線程地區設定的每個線程中變更地區設定。 若要在單一線程或應用程式的一部分變更地區設定,只要在該線程或程式代碼的一部分中建立 對象的實例 locale
即可。
注意
呼叫 locale::global 會同時變更C++標準連結庫和 C 運行時間連結庫的地區設定。 不過,呼叫 setlocale 只會變更 C 運行時間連結庫的地區設定;C++標準連結庫不會受到影響。
下列範例示範如何使用 setlocale 函式、 地區設定類別和 _configthreadlocale 函式,在數個不同的案例中變更應用程式的地區設定。
範例:變更已啟用每個線程地區設定的地區設定
在此範例中,主線程會繁衍兩個子線程。 第一個線程 Thread A 會藉由呼叫 _configthreadlocale(_ENABLE_PER_THREAD_LOCALE)
來啟用每個線程的地區設定。 第二個線程 Thread B 以及主線程不會啟用每個線程的地區設定。 線程 A 接著會繼續使用 C 執行時間連結庫的 setlocale 函式來變更地區設定。
由於線程 A 已啟用個別線程地區設定,因此只有線程 A 中的 C 執行時間連結庫函式會使用 「french」 地區設定來啟動。 線程 B 和主線程中的 C 執行時間連結庫函式會繼續使用 「C」 地區設定。 此外,由於 setlocale 不會影響C++標準連結庫地區設定,因此所有C++標準連結庫對象都會繼續使用 “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"
範例:變更已啟用每個線程地區設定的全域地區設定
在此範例中,主線程會繁衍兩個子線程。 第一個線程 Thread A 會藉由呼叫 _configthreadlocale(_ENABLE_PER_THREAD_LOCALE)
來啟用每個線程的地區設定。 第二個線程 Thread B 以及主線程不會啟用每個線程的地區設定。 線程 A 接著會繼續使用 C++ 標準連結庫的地區設定::global 方法來變更地區設定。
由於線程 A 已啟用個別線程地區設定,因此只有線程 A 中的 C 執行時間連結庫函式會使用 「french」 地區設定來啟動。 線程 B 和主線程中的 C 執行時間連結庫函式會繼續使用 「C」 地區設定。 不過,由於locale::global方法會變更地區設定「全域」,因此所有線程中的所有C++標準連結庫物件都會使用 「french」 地區設定開始。
// 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"
範例:變更未啟用每個線程地區設定的地區設定
在此範例中,主線程會繁衍兩個子線程。 第一個線程 Thread A 會藉由呼叫 _configthreadlocale(_ENABLE_PER_THREAD_LOCALE)
來啟用每個線程的地區設定。 第二個線程 Thread B 以及主線程不會啟用每個線程的地區設定。 線程 B 接著會繼續使用 C 執行時間連結庫的 setlocale 函式來變更地區設定。
由於線程 B 未啟用個別線程地區設定,因此 C 執行時間連結庫會在線程 B 和主線程中使用「法文」地區設定來啟動。 線程 A 中的 C 執行時間連結庫函式會繼續使用 「C」 地區設定,因為線程 A 已啟用每個線程的地區設定。 此外,由於 setlocale 不會影響C++標準連結庫地區設定,因此所有C++標準連結庫對象都會繼續使用 “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"
範例:變更未啟用每個線程地區設定的全域地區設定
在此範例中,主線程會繁衍兩個子線程。 第一個線程 Thread A 會藉由呼叫 _configthreadlocale(_ENABLE_PER_THREAD_LOCALE)
來啟用每個線程的地區設定。 第二個線程 Thread B 以及主線程不會啟用每個線程的地區設定。 線程 B 接著會繼續使用 C++ 標準連結庫的地區設定::global 方法來變更地區設定。
由於線程 B 未啟用個別線程地區設定,因此 C 執行時間連結庫會在線程 B 和主線程中使用「法文」地區設定來啟動。 線程 A 中的 C 執行時間連結庫函式會繼續使用 「C」 地區設定,因為線程 A 已啟用每個線程的地區設定。 不過,由於locale::global方法會變更地區設定「全域」,因此所有線程中的所有C++標準連結庫物件都會使用 「french」 地區設定開始。
// 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"
另請參閱
舊版程式碼的多執行緒支援 (Visual C++)
_beginthread、_beginthreadex
_configthreadlocale
setlocale
國際化
地區設定
<clocale>
<地區設定>
locale 類別