Share via


Multithreading dan Lokal

Pustaka Runtime C dan Pustaka Standar C++ menyediakan dukungan untuk mengubah lokal program Anda. Topik ini membahas masalah yang muncul saat menggunakan fungsionalitas lokal kedua pustaka dalam aplikasi multithreaded.

Keterangan

Dengan Pustaka Runtime C, Anda dapat membuat aplikasi multithread menggunakan _beginthread fungsi dan _beginthreadex . Topik ini hanya mencakup aplikasi multithread yang dibuat menggunakan fungsi-fungsi ini. Untuk informasi selengkapnya, lihat _beginthread, _beginthreadex.

Untuk mengubah lokal menggunakan Pustaka Runtime C, gunakan fungsi setlocale . Di versi Visual C++sebelumnya, fungsi ini akan selalu memodifikasi lokal di seluruh aplikasi. Sekarang ada dukungan untuk mengatur lokal berdasarkan per utas. Ini dilakukan menggunakan fungsi _configthreadlocale . Untuk menentukan bahwa setlocale hanya boleh mengubah lokal di utas saat ini, panggil _configthreadlocale(_ENABLE_PER_THREAD_LOCALE) di utas tersebut. Sebaliknya, panggilan _configthreadlocale(_DISABLE_PER_THREAD_LOCALE) akan menyebabkan utas tersebut menggunakan lokal global, dan setiap panggilan ke setlocale di utas tersebut akan mengubah lokal di semua utas yang belum mengaktifkan lokal per utas secara eksplisit.

Untuk mengubah lokal menggunakan Pustaka Runtime C++, gunakan Kelas lokal. Dengan memanggil metode lokal::global , Anda mengubah lokal di setiap utas yang belum mengaktifkan lokal per utas secara eksplisit. Untuk mengubah lokal dalam satu utas atau bagian aplikasi, cukup buat instans locale objek di utas atau bagian kode tersebut.

Catatan

Memanggil lokal::global mengubah lokal untuk Pustaka Standar C++ dan Pustaka Runtime C. Namun, setlocale panggilan hanya mengubah lokal untuk Pustaka Runtime C; Pustaka Standar C++ tidak terpengaruh.

Contoh berikut menunjukkan cara menggunakan fungsi setlocale , Kelas lokal, dan fungsi _configthreadlocale untuk mengubah lokal aplikasi dalam beberapa skenario yang berbeda.

Contoh: Ubah lokal dengan lokal per utas diaktifkan

Dalam contoh ini, utas utama menelurkan dua utas anak. Utas pertama, Thread A, memungkinkan lokal per utas dengan memanggil _configthreadlocale(_ENABLE_PER_THREAD_LOCALE). Utas kedua, Thread B, serta utas utama, tidak mengaktifkan lokal per utas. Utas A kemudian melanjutkan untuk mengubah lokal menggunakan fungsi setlocale dari Pustaka Runtime C.

Karena Thread A mengaktifkan lokal per utas, hanya C Runtime Library yang berfungsi di Thread A mulai menggunakan lokal "prancis". Pustaka Runtime C berfungsi di Thread B dan di utas utama terus menggunakan lokal "C". Selain itu, karena setlocale tidak memengaruhi lokal Pustaka Standar C++, semua objek Pustaka Standar C++ terus menggunakan lokal "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"

Contoh: Ubah lokal global dengan lokal per utas diaktifkan

Dalam contoh ini, utas utama menelurkan dua utas anak. Utas pertama, Thread A, memungkinkan lokal per utas dengan memanggil _configthreadlocale(_ENABLE_PER_THREAD_LOCALE). Utas kedua, Thread B, serta utas utama, tidak mengaktifkan lokal per utas. Thread A kemudian melanjutkan untuk mengubah lokal menggunakan metode lokal::global C++ Standard Library.

Karena Thread A mengaktifkan lokal per utas, hanya C Runtime Library yang berfungsi di Thread A mulai menggunakan lokal "prancis". Pustaka Runtime C berfungsi di Thread B dan di utas utama terus menggunakan lokal "C". Namun, karena metode lokal::global mengubah lokal "global", semua objek Pustaka Standar C++ di semua utas mulai menggunakan lokal "prancis".

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

Contoh: Ubah lokal tanpa lokal per utas diaktifkan

Dalam contoh ini, utas utama menelurkan dua utas anak. Utas pertama, Thread A, memungkinkan lokal per utas dengan memanggil _configthreadlocale(_ENABLE_PER_THREAD_LOCALE). Utas kedua, Thread B, serta utas utama, tidak mengaktifkan lokal per utas. Thread B kemudian melanjutkan untuk mengubah lokal menggunakan fungsi setlocale dari Pustaka Runtime C.

Karena Thread B tidak mengaktifkan lokal per utas, Pustaka Runtime C berfungsi di Thread B dan di utas utama mulai menggunakan lokal "prancis". Pustaka Runtime C berfungsi di Thread A terus menggunakan lokal "C" karena Utas A mengaktifkan lokal per utas. Selain itu, karena setlocale tidak memengaruhi lokal Pustaka Standar C++, semua objek Pustaka Standar C++ terus menggunakan lokal "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"

Contoh: Mengubah lokal global tanpa lokal per utas diaktifkan

Dalam contoh ini, utas utama menelurkan dua utas anak. Utas pertama, Thread A, memungkinkan lokal per utas dengan memanggil _configthreadlocale(_ENABLE_PER_THREAD_LOCALE). Utas kedua, Thread B, serta utas utama, tidak mengaktifkan lokal per utas. Thread B kemudian melanjutkan untuk mengubah lokal menggunakan metode lokal::global dari Pustaka Standar C++.

Karena Thread B tidak mengaktifkan lokal per utas, Pustaka Runtime C berfungsi di Thread B dan di utas utama mulai menggunakan lokal "prancis". Pustaka Runtime C berfungsi di Thread A terus menggunakan lokal "C" karena Utas A mengaktifkan lokal per utas. Namun, karena metode lokal::global mengubah lokal "global", semua objek Pustaka Standar C++ di semua utas mulai menggunakan lokal "prancis".

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

Baca juga

Dukungan Multithreading untuk Kode Lama (Visual C++)
_beginthread, _beginthreadex
_configthreadlocale
setlocale
Internasionalisasi
Lokal
<kloning>
<lokal>
Kelas lokal