Pertanyaan Threadsafe vs peserta kembali


Baru-baru ini, saya mengajukan pertanyaan, dengan judul sebagai "Apakah benang malloc aman?", dan di dalam itu saya bertanya, "Apakah Malocad kembali-peserta?"

Saya mendapat kesan bahwa semua peserta kembali aman.

Apakah anggapan ini salah?


76
2018-05-13 08:43


asal


Jawaban:


Fungsi re-entrant tidak bergantung pada variabel global yang terpapar di header library C. mengambil strtok () vs strtok_r () misalnya di C.

Beberapa fungsi memerlukan tempat untuk menyimpan fungsi 'sedang berlangsung', fungsi re-entran memungkinkan Anda menentukan penunjuk ini dalam penyimpanan utas sendiri, bukan di global. Karena penyimpanan ini eksklusif untuk fungsi panggilan, itu dapat terganggu dan masuk kembali (peserta kembali) dan karena dalam banyak kasus, pengecualian timbal balik di luar apa yang tidak diperlukan oleh fungsi ini untuk berfungsi, mereka sering dianggap sebagai utas aman. Namun ini tidak dijamin oleh definisi.

errno, bagaimanapun, adalah kasus yang sedikit berbeda pada sistem POSIX (dan cenderung menjadi eksentrik dalam penjelasan tentang bagaimana semua ini bekerja) :)

Singkatnya, reentrant sering berarti utas aman (seperti dalam "gunakan versi reentrant dari fungsi itu jika Anda menggunakan utas"), tetapi utas aman tidak selalu berarti peserta ulang (atau sebaliknya). Ketika Anda melihat keamanan benang, konkurensi adalah apa yang perlu Anda pikirkan. Jika Anda harus menyediakan sarana penguncian dan eksklusi bersama untuk menggunakan fungsi, maka fungsi tersebut tidak secara inheren aman-thread.

Namun, tidak semua fungsi perlu diperiksa untuk keduanya. malloc() tidak perlu menjadi reentrant, itu tidak tergantung pada apa pun di luar lingkup entry point untuk setiap thread yang diberikan (dan itu sendiri thread safe).

Fungsi yang mengembalikan nilai yang dialokasikan secara statis adalah tidak benang aman tanpa menggunakan mutex, futex, atau mekanisme penguncian atom lainnya. Namun, mereka tidak perlu menjadi reentrant jika mereka tidak akan terganggu.

yaitu.:

static char *foo(unsigned int flags)
{
  static char ret[2] = { 0 };

  if (flags & FOO_BAR)
    ret[0] = 'c';
  else if (flags & BAR_FOO)
    ret[0] = 'd';
  else
    ret[0] = 'e';

  ret[1] = 'A';

  return ret;
}

Jadi, seperti yang Anda lihat, memiliki beberapa utas menggunakan itu tanpa semacam penguncian akan menjadi bencana .. tetapi tidak memiliki tujuan menjadi peserta kembali. Anda akan mengalami itu ketika memori yang dialokasikan secara dinamis adalah tabu pada beberapa platform yang tertanam.

Dalam pemrograman fungsional murni, sering masuk kembali tidak menyiratkan keamanan benang, itu akan tergantung pada perilaku fungsi yang ditetapkan atau anonim yang diteruskan ke titik masuk fungsi, rekursi, dll.

Cara yang lebih baik untuk menempatkan 'benang aman' adalah aman untuk akses bersamaan , yang lebih menggambarkan kebutuhan.


38
2018-05-13 08:55



Itu tergantung pada definisi. Sebagai contoh Qt digunakan pengikut:

  • Fungsi thread-safe * dapat dipanggil secara bersamaan dari beberapa utas, bahkan ketika invokasi menggunakan data bersama, karena semua referensi ke data bersama diserialkan.

  • SEBUAH reentrant fungsi juga dapat dipanggil secara bersamaan dari beberapa utas, tetapi hanya jika setiap panggilan menggunakan datanya sendiri.

Oleh karena itu, a aman dari benang fungsi selalu reentrant, tetapi a reentrant fungsi tidak selalu aman-thread.

Dengan ekstensi, kelas dikatakan reentrant jika fungsi anggotanya dapat dipanggil dengan aman dari beberapa utas, selama setiap utas menggunakan kelas yang berbeda dari kelas. Kelasnya aman dari benang jika fungsi anggotanya dapat dipanggil dengan aman dari beberapa utas, meskipun semua utas menggunakan kelas yang sama.

tetapi mereka juga memperingatkan:

catatan: Terminologi dalam domain multithreading tidak sepenuhnya standar. POSIX menggunakan definisi reentrant dan thread-safe yang agak berbeda untuk API C-nya. Saat menggunakan pustaka kelas C ++ berorientasi objek lainnya dengan Qt, pastikan definisi dipahami.


54
2018-05-13 09:08



TL; DR: Suatu fungsi dapat menjadi reentrant, thread-safe, keduanya atau tidak.

Artikel Wikipedia untuk keamanan benang dan reentrancy sangat layak dibaca. Berikut beberapa kutipan:

Suatu fungsi adalah aman dari benang jika:

hanya memanipulasi struktur data bersama di   cara yang menjamin eksekusi yang aman dengan beberapa   utas pada saat yang sama.

Suatu fungsi adalah reentrant jika:

itu bisa terganggu kapan saja selama eksekusinya   dan kemudian dengan aman dipanggil lagi ("re-enter") sebelum itu   eksekusi sebelumnya eksekusi lengkap.

Sebagai contoh kemungkinan reentrance, Wikipedia memberikan contoh fungsi yang dirancang untuk dipanggil oleh interupsi sistem: misalkan sudah berjalan ketika interrupt lain terjadi. Tapi jangan berpikir Anda aman hanya karena Anda tidak berkode dengan interupsi sistem: Anda dapat memiliki masalah reentrance dalam program single-threaded jika Anda menggunakan callback atau fungsi rekursif.

Kunci untuk menghindari kebingungan adalah merujuk reentrant   hanya satu thread yang dieksekusi. Ini adalah konsep dari waktu kapan   tidak ada sistem operasi multitasking.

Contoh

(Sedikit dimodifikasi dari artikel Wikipedia)

Contoh 1: tidak aman-thread, bukan reentrant

/* As this function uses a non-const global variable without
   any precaution, it is neither reentrant nor thread-safe. */

int t;

void swap(int *x, int *y)
{
    t = *x;
    *x = *y;
    *y = t;
}

Contoh 2: aman dari thread, bukan reentrant

/* We use a thread local variable: the function is now
   thread-safe but still not reentrant (within the
   same thread). */

__thread int t;

void swap(int *x, int *y)
{
    t = *x;
    *x = *y;
    *y = t;
}

Contoh 3: tidak aman-thread, reentrant

/* We save the global state in a local variable and we restore
   it at the end of the function.  The function is now reentrant
   but it is not thread safe. */

int t;

void swap(int *x, int *y)
{
    int s;
    s = t;
    t = *x;
    *x = *y;
    *y = t;
    t = s;
}

Contoh 4: aman-thread, reentrant

/* We use a local variable: the function is now
   thread-safe and reentrant, we have ascended to
   higher plane of existence.  */

void swap(int *x, int *y)
{
    int t;
    t = *x;
    *x = *y;
    *y = t;
}

52
2017-10-30 22:34