分享方式:


多執行緒和地區設定

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++ 執行時間程式庫變更地區設定,請使用 地區設定類別 。 藉由呼叫 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 類別