Dalam errno.h
, variabel ini dinyatakan sebagai extern int errno;
pertanyaan saya, apakah aman untuk memeriksa errno
nilai setelah beberapa panggilan atau menggunakan perror () dalam kode multi-utas. Apakah ini variabel thread aman? Jika tidak, lalu apa alternatifnya?
Saya menggunakan linux dengan gcc pada arsitektur x86.
c
linux
multithreading
gcc
vinit dhatrak
sumber
sumber
Jawaban:
Ya, aman untuk thread. Di Linux, variabel errno global bersifat spesifik-utas. POSIX mengharuskan errno menjadi threadsafe.
Lihat http://www.unix.org/whitepapers/reentrant.html
Lihat juga http://linux.die.net/man/3/errno
sumber
# if !defined _LIBC || defined _LIBC_REENTRANT
, _LIBC tidak didefinisikan ketika mengkompilasi program normal. Pokoknya, jalankan echo#include <errno.h>' | gcc -E -dM -xc -
dan lihat perbedaannya dengan dan tanpa -pthread. errno#define errno (*__errno_location ())
dalam kedua kasus.Iya
Errno bukan variabel sederhana lagi, itu sesuatu yang rumit di belakang layar, khusus untuk itu agar aman.
Lihat
$ man 3 errno
:Kami dapat memeriksa ulang:
sumber
Inilah yang dikatakan standar C:
Secara umum,
errno
adalah makro yang memanggil fungsi mengembalikan alamat nomor kesalahan untuk utas saat ini, lalu menyimpikannya.Inilah yang saya miliki di Linux, di /usr/include/bits/errno.h:
Pada akhirnya, ini menghasilkan kode semacam ini:
sumber
Pada banyak sistem Unix, kompilasi dengan
-D_REENTRANT
memastikan bahwaerrno
thread-safe.Sebagai contoh:
sumber
-D_REENTRANT
. Silakan merujuk pada diskusi tentang jawaban lain untuk pertanyaan yang sama.-D_XOPEN_SOURCE=500
atau-D_XOPEN_SOURCE=600
. Tidak semua orang mengganggu untuk memastikan bahwa lingkungan POSIX ditentukan - dan kemudian-D_REENTRANT
dapat menyimpan daging Anda. Tetapi Anda masih harus berhati-hati - pada setiap platform - untuk memastikan Anda mendapatkan perilaku yang diinginkan.errno
yang meluas ke nilai yang dapat dimodifikasi (201) yang memiliki jenisint
dan durasi penyimpanan lokal, nilai yang ditetapkan ke angka kesalahan positif oleh beberapa fungsi perpustakaan. Jika definisi makro ditekan untuk mengakses objek yang sebenarnya, atau program mendefinisikan pengidentifikasi dengan namaerrno
, perilaku tidak terdefinisi. [... lanjutan ...]errno
tidak perlu menjadi pengidentifikasi suatu objek. Mungkin diperluas ke nilai yang dapat dimodifikasi yang dihasilkan dari panggilan fungsi (misalnya,*errno()
). Teks utama berlanjut: Nilai errno di utas awal adalah nol pada startup program (nilai awal errno di utas lain adalah nilai yang tidak ditentukan), tetapi tidak pernah disetel ke nol oleh fungsi pustaka apa pun. POSIX menggunakan standar C99 yang tidak mengenali utas. [... juga melanjutkan ...]Ini dari
<sys/errno.h>
pada Mac saya:Jadi
errno
sekarang fungsi__error()
. Fungsi ini diimplementasikan agar aman.sumber
ya , seperti yang dijelaskan di halaman manual errno dan balasan lainnya, errno adalah variabel lokal thread.
Namun , ada detail konyol yang bisa dengan mudah dilupakan. Program harus menyimpan dan mengembalikan kesalahan pada penangan sinyal yang menjalankan panggilan sistem. Ini karena sinyal akan ditangani oleh salah satu utas proses yang dapat menimpa nilainya.
Oleh karena itu, penangan sinyal harus menyimpan dan mengembalikan errno. Sesuatu seperti:
sumber
Saya pikir jawabannya adalah "itu tergantung". Pustaka runtime C aman-thread biasanya menerapkan errno sebagai panggilan fungsi (makro meluas ke suatu fungsi) jika Anda membuat kode berulir dengan flag yang benar.
sumber
Kita dapat memeriksa dengan menjalankan program sederhana pada mesin.
Menjalankan program ini dan Anda dapat melihat alamat yang berbeda untuk errno di setiap utas. Output dari pelarian pada mesin saya tampak seperti: -
Perhatikan bahwa alamat berbeda untuk semua utas.
sumber