Bagikan melalui


Thread Local Storage (TLS)

Thread Local Storage (TLS) adalah metode di mana setiap utas dalam proses multithread tertentu dapat mengalokasikan lokasi untuk menyimpan data khusus utas. Data khusus utas yang terikat secara dinamis (run-time) didukung dengan cara TLS API (TlsAlloc). Win32 dan pengkompilasi Microsoft C++ sekarang mendukung data per utas yang terikat secara statis selain implementasi API yang ada.

Implementasi Kompilator untuk TLS

C++11: Penentu thread_local kelas penyimpanan adalah cara yang disarankan untuk menentukan penyimpanan lokal utas untuk objek dan anggota kelas. Untuk informasi selengkapnya, lihat Kelas penyimpanan (C++).

MSVC juga menyediakan atribut khusus Microsoft, utas, sebagai pengubah kelas penyimpanan yang diperluas. __declspec Gunakan kata kunci untuk mendeklarasikan thread variabel. Misalnya, kode berikut mendeklarasikan variabel lokal utas bilangan bulat dan menginisialisasinya dengan nilai:

__declspec( thread ) int tls_i = 1;

Aturan dan batasan

Panduan berikut harus diamati saat mendeklarasikan objek dan variabel lokal utas yang terikat secara statis. Panduan ini berlaku untuk utas dan thread_local:

  • Atribut thread hanya dapat diterapkan ke deklarasi dan definisi kelas dan data. Ini tidak dapat digunakan pada deklarasi atau definisi fungsi. Misalnya, kode berikut menghasilkan kesalahan pengompilasi:

    __declspec( thread )void func();     // This will generate an error.
    
  • Pengubah thread hanya dapat ditentukan pada item data sejauh static mana. Itu termasuk objek data global (baik static dan extern), objek statis lokal, dan anggota data statis kelas C++. Objek data otomatis tidak dapat dideklarasikan dengan thread atribut . Kode berikut menghasilkan kesalahan pengkompilasi:

    void func1()
    {
        __declspec( thread )int tls_i;            // This will generate an error.
    }
    
    int func2(__declspec( thread )int tls_i )     // This will generate an error.
    {
        return tls_i;
    }
    
  • Deklarasi dan definisi objek lokal utas semuanya harus menentukan thread atribut . Misalnya, kode berikut menghasilkan kesalahan:

    #define Thread  __declspec( thread )
    extern int tls_i;        // This will generate an error, since the
    int __declspec( thread )tls_i;        // declaration and definition differ.
    
  • Atribut thread tidak dapat digunakan sebagai pengubah jenis. Misalnya, kode berikut menghasilkan kesalahan pengompilasi:

    char __declspec( thread ) *ch;        // Error
    
  • Karena deklarasi objek C++ yang menggunakan thread atribut diizinkan, dua contoh berikut setara secara semantik:

    __declspec( thread ) class B
    {
    // Code
    } BObject;  // OK--BObject is declared thread local.
    
    class B
    {
    // Code
    };
    __declspec( thread ) B BObject;  // OK--BObject is declared thread local.
    
  • Alamat objek lokal utas tidak dianggap konstanta, dan ekspresi apa pun yang melibatkan alamat tersebut tidak dianggap sebagai ekspresi konstanta. Dalam C standar, efeknya adalah melarang penggunaan alamat variabel lokal utas sebagai penginisialisasi untuk objek atau penunjuk. Misalnya, kode berikut ditandai sebagai kesalahan oleh pengkompilasi C:

    __declspec( thread ) int tls_i;
    int *p = &tls_i;       //This will generate an error in C.
    

    Pembatasan ini tidak berlaku di C++. Karena C++ memungkinkan inisialisasi dinamis semua objek, Anda dapat menginisialisasi objek dengan menggunakan ekspresi yang menggunakan alamat variabel lokal utas. Ini dilakukan seperti pembangunan objek lokal utas. Misalnya, kode yang ditampilkan sebelumnya tidak menghasilkan kesalahan saat dikompilasi sebagai file sumber C++. Alamat variabel lokal utas hanya berlaku selama utas tempat alamat diambil masih ada.

  • Standar C memungkinkan inisialisasi objek atau variabel dengan ekspresi yang melibatkan referensi ke dirinya sendiri, tetapi hanya untuk objek tingkat nonstatis. Meskipun C++ umumnya memungkinkan inisialisasi dinamis objek dengan ekspresi yang melibatkan referensi ke dirinya sendiri, inisialisasi semacam ini tidak diizinkan dengan objek lokal utas. Contohnya:

    __declspec( thread )int tls_i = tls_i;                // Error in C and C++
    int j = j;                               // OK in C++, error in C
    __declspec( thread )int tls_i = sizeof( tls_i )       // Legal in C and C++
    

    Ekspresi sizeof yang menyertakan objek yang diinisialisasi tidak mewakili referensi ke dirinya sendiri, dan diaktifkan di C dan C++.

    C++ tidak mengizinkan inisialisasi dinamis data utas tersebut karena kemungkinan peningkatan di masa mendatang ke fasilitas penyimpanan lokal utas.

  • Pada sistem operasi Windows sebelum Windows Vista, __declspec( thread ) memiliki beberapa batasan. Jika DLL mendeklarasikan data atau objek apa pun sebagai __declspec( thread ), itu dapat menyebabkan kesalahan perlindungan jika dimuat secara dinamis. Setelah DLL dimuat dengan LoadLibrary, hal ini menyebabkan kegagalan sistem setiap kali kode mereferensikan __declspec( thread ) data. Karena ruang variabel global untuk utas dialokasikan pada run time, ukuran ruang ini didasarkan pada perhitungan persyaratan aplikasi ditambah persyaratan semua DLL yang ditautkan secara statis. Saat Anda menggunakan LoadLibrary, Anda tidak dapat memperluas ruang ini untuk memungkinkan variabel lokal utas yang dideklarasikan dengan __declspec( thread ). Gunakan API TLS, seperti TlsAlloc, di DLL Anda untuk mengalokasikan TLS jika DLL mungkin dimuat dengan LoadLibrary.

Baca juga

Multithreading dengan C dan Win32