Condividi tramite


Multithreading e impostazioni internazionali

Aggiornamento: novembre 2007

Sia la libreria di runtime C che la libreria standard di C++ forniscono supporto per la modifica delle impostazioni internazionali del programma in uso. In questo argomento vengono illustrati i problemi che possono sorgere durante l'utilizzo della funzionalità relativa alle impostazioni internazionali di entrambe le librerie in un'applicazione multithreading.

Note

La libreria di runtime C consente di creare applicazioni multithreading utilizzando le funzioni _beginthread e _beginthreadex. In questo argomento vengono illustrate solo le applicazioni multithreading create mediante queste funzioni. Per ulteriori informazioni, vedere _beginthread, _beginthreadex.

Per modificare le impostazioni internazionali mediante la libreria di runtime C, utilizzare la funzione setlocale. Nelle versioni precedenti di Visual C++ questa funzione consente di modificare le impostazioni locali dell'intera applicazione. La nuova versione supporta invece la modifica delle impostazioni internazionali per thread mediante la funzione _configthreadlocale. Per specificare la modifica delle impostazioni internazionali tramite setlocale solo nel thread corrente, chiamare _configthreadlocale(_ENABLE_PER_THREAD_LOCALE) in tale thread. Se invece si chiama _configthreadlocale(_DISABLE_PER_THREAD_LOCALE), nel thread verranno utilizzate le impostazioni internazionali globali e tutte le chiamate a setlocale nel thread comporteranno la modifica delle impostazioni internazionali in tutti i thread nei quali non siano state esplicitamente abilitate le impostazioni internazionali per thread.

Per modificare le impostazioni internazionali mediante la libreria di runtime C++, utilizzare la funzione locale Class. Il metodo locale::global consente di modificare le impostazioni internazionali in tutti i thread per i quali non siano state esplicitamente abilitate le impostazioni internazionali per thread. Per modificare le impostazioni internazionali in un solo thread o in una parte di un'applicazione, è sufficiente creare un'istanza di un oggetto locale nel thread o nella parte di codice.

Nota:

Il metodo locale::global consente di modificare le impostazioni internazionali per la libreria standard di C++ e per la libreria di runtime C. Se si chiama setlocale, tuttavia, verranno modificate solo le impostazioni internazionali per la libreria di runtime C, mentre la libreria standard di C++ non verrà interessata.

Negli esempi riportati di seguito viene illustrato l'utilizzo delle funzioni setlocale, locale Class e _configthreadlocale per modificare le impostazioni internazionali di un'applicazione in diversi scenari.

Esempio

In questo esempio il thread principale genera due thread figlio. Nel primo, Thread A, sono abilitate le impostazioni internazionali per thread mediante la chiamata a _configthreadlocale(_ENABLE_PER_THREAD_LOCALE). Nel secondo thread, Thread B, come per il thread principale, le impostazioni internazionali per thread non sono abilitate. Nel Thread A le impostazioni internazionali vengono modificate mediante la funzione setlocale della libreria di runtime C.

Poiché per il Thread A le impostazioni internazionali sono configurate per thread, solo per le funzioni della libreria di runtime nel Thread A vengono utilizzate le impostazioni internazionali per il francese. Le funzioni della libreria di runtime C nel Thread B e nel thread principale continueranno a utilizzare le impostazioni internazionali "C". La funzione setlocale inoltre non influenza le impostazioni internazionali della libreria standard di C++, pertanto in tutti gli oggetti della libreria standard C++ verranno utilizzate le impostazioni internazionali "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"

In questo esempio il thread principale genera due thread figlio. Nel primo, Thread A, sono abilitate le impostazioni internazionali per thread mediante la chiamata a _configthreadlocale(_ENABLE_PER_THREAD_LOCALE). Nel secondo thread, Thread B, come per il thread principale, le impostazioni internazionali per thread non sono abilitate. Nel Thread A le impostazioni internazionali vengono modificate mediante il metodo locale::global della libreria standard di C++.

Poiché per il Thread A le impostazioni internazionali sono configurate per thread, solo per le funzioni della libreria di runtime nel Thread A vengono utilizzate le impostazioni internazionali per il francese. Le funzioni della libreria di runtime C nel Thread B e nel thread principale continueranno a utilizzare le impostazioni internazionali "C". Poiché tuttavia il metodo locale::global modifica le impostazioni internazionali globalmente, tutti gli oggetti della libreria standard di C++ in tutti i thread utilizzeranno le impostazioni internazionali per il francese.

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

In questo esempio il thread principale genera due thread figlio. Nel primo, Thread A, sono abilitate le impostazioni internazionali per thread mediante la chiamata a _configthreadlocale(_ENABLE_PER_THREAD_LOCALE). Nel secondo thread, Thread B, come per il thread principale, le impostazioni internazionali per thread non sono abilitate. Nel Thread B le impostazioni internazionali vengono modificate mediante la funzione setlocale della libreria di runtime C.

Poiché nel Thread B non sono abilitate le impostazioni internazionali per thread, le funzioni della libreria di runtime C nel Thread B e nel thread principale utilizzeranno le impostazioni internazionali per il francese. Le funzioni della libreria di runtime C nel Thread A continueranno a utilizzare le impostazioni internazionali "C" poiché nel Thread A sono attivate le impostazioni internazionali per thread. La funzione setlocale inoltre non influenza le impostazioni internazionali della libreria standard di C++, pertanto in tutti gli oggetti della libreria standard C++ verranno utilizzate le impostazioni internazionali "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"

In questo esempio il thread principale genera due thread figlio. Nel primo, Thread A, sono abilitate le impostazioni internazionali per thread mediante la chiamata a _configthreadlocale(_ENABLE_PER_THREAD_LOCALE). Nel secondo thread, Thread B, come per il thread principale, le impostazioni internazionali per thread non sono abilitate. Nel Thread B le impostazioni internazionali vengono modificate mediante il metodo locale::global della libreria standard di C++.

Poiché nel Thread B non sono abilitate le impostazioni internazionali per thread, le funzioni della libreria di runtime C nel Thread B e nel thread principale utilizzeranno le impostazioni internazionali per il francese. Le funzioni della libreria di runtime C nel Thread A continueranno a utilizzare le impostazioni internazionali "C" poiché nel Thread A sono attivate le impostazioni internazionali per thread. Poiché tuttavia il metodo locale::global modifica le impostazioni internazionali globalmente, tutti gli oggetti della libreria standard di C++ in tutti i thread utilizzeranno le impostazioni internazionali per il francese.

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

Vedere anche

Concetti

Multithreading

Riferimenti

_beginthread, _beginthreadex

_configthreadlocale

setlocale

Internationalization

Locale

<clocale>

<locale>

locale Class