Saya akan membaca buku ini , Pemrograman Linux Lanjut oleh Mark Mitchell, Jeffrey Oldham, dan Alex Samuel. Ini dari tahun 2001, jadi agak tua. Tapi bagaimanapun saya merasa cukup baik.
Namun, saya sampai pada titik ketika ia menyimpang dari apa yang diproduksi Linux saya di output shell. Pada halaman 92 (116 dalam penampil), bab 4.5 Implementasi Utas GNU / Linux dimulai dengan paragraf yang berisi pernyataan ini:
Implementasi utas POSIX pada GNU / Linux berbeda dari implementasi utas pada banyak sistem mirip UNIX lainnya dalam cara yang penting: pada GNU / Linux, utas diimplementasikan sebagai proses.
Ini sepertinya titik kunci dan kemudian diilustrasikan dengan kode C. Output dalam buku ini adalah:
main thread pid is 14608
child thread pid is 14610
Dan di Ubuntu 16.04 saya adalah:
main thread pid is 3615
child thread pid is 3615
ps
output mendukung ini.
Saya kira sesuatu pasti telah berubah antara tahun 2001 dan sekarang.
Sub bab berikutnya pada halaman berikutnya, 4.5.1 Penanganan Sinyal, dibangun berdasarkan pernyataan sebelumnya:
Perilaku interaksi antara sinyal dan utas bervariasi dari satu sistem mirip UNIX ke yang lain. Di GNU / Linux, perilaku ditentukan oleh fakta bahwa utas diimplementasikan sebagai proses.
Dan sepertinya ini akan menjadi lebih penting nanti di buku ini. Bisakah seseorang menjelaskan apa yang terjadi di sini?
Saya pernah melihat yang satu ini. Apakah kernel Linux benar-benar proses kernel? , tapi itu tidak banyak membantu. Saya bingung.
Ini adalah kode C:
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
void* thread_function (void* arg)
{
fprintf (stderr, "child thread pid is %d\n", (int) getpid ());
/* Spin forever. */
while (1);
return NULL;
}
int main ()
{
pthread_t thread;
fprintf (stderr, "main thread pid is %d\n", (int) getpid ());
pthread_create (&thread, NULL, &thread_function, NULL);
/* Spin forever. */
while (1);
return 0;
}
getpid
mengembalikan apa yang disebut ID grup thread dan untuk mendapatkan ID unik untuk suatu proses yang perlu Anda gunakangettid
. Namun, selain kernel, kebanyakan orang dan alat akan menyebut grup utas proses, dan menyebut proses utas, untuk konsistensi dengan sistem lain.Jawaban:
Saya pikir ini bagian dari
clone(2)
halaman manual dapat menjelaskan perbedaannya. PID:Frase "utas diimplementasikan sebagai proses" mengacu pada masalah utas yang memiliki PID terpisah sebelumnya. Pada dasarnya, Linux pada awalnya tidak memiliki utas dalam suatu proses, hanya proses terpisah (dengan PID terpisah) yang mungkin memiliki beberapa sumber daya bersama, seperti memori virtual atau deskriptor file.
CLONE_THREAD
dan pemisahan ID proses (*) dan ID utas membuat perilaku Linux lebih mirip sistem lain dan lebih seperti persyaratan POSIX dalam pengertian ini. Meskipun secara teknis OS masih belum memiliki implementasi terpisah untuk utas dan proses.Penanganan sinyal adalah area bermasalah lainnya dengan implementasi lama, hal ini dijelaskan secara lebih rinci dalam makalah @FooF yang merujuk pada jawaban mereka .
Seperti disebutkan dalam komentar, Linux 2.4 juga dirilis pada tahun 2001, tahun yang sama dengan buku, jadi tidak mengherankan berita tidak sampai ke cetakan itu.
sumber
Anda benar, memang "sesuatu harus berubah antara tahun 2001 dan sekarang". Buku yang Anda baca menggambarkan dunia menurut implementasi historis pertama utas POSIX di Linux, disebut LinuxThreads (lihat juga artikel Wikipedia untuk sebagian).
LinuxThreads memiliki beberapa masalah kompatibilitas dengan standar POSIX - misalnya utas tidak berbagi PID - dan beberapa masalah serius lainnya. Untuk memperbaiki kekurangan ini, implementasi lain yang disebut NPTL (Native POSIX Thread Library) dipelopori oleh Red Hat untuk menambahkan dukungan kernel dan ruang perpustakaan pengguna yang diperlukan untuk mencapai kepatuhan POSIX yang lebih baik (mengambil bagian yang baik dari proyek implementasi ulang lain yang bersaing oleh IBM bernama NGPT (" Next Generation Posixs Threads "), lihat artikel Wikipedia di NPTL ). Bendera tambahan yang ditambahkan ke
clone(2)
system call (terutamaCLONE_THREAD
yang@ikkkachu
menunjukkan jawabannya ) mungkin merupakan bagian paling jelas dari modifikasi kernel. Bagian ruang pengguna dari karya tersebut akhirnya dimasukkan ke dalam GNU C Library.Masih saat ini beberapa SDK Linux tertanam menggunakan implementasi LinuxThreads lama karena mereka menggunakan versi jejak memori yang lebih kecil dari LibC yang disebut uClibc (juga disebut µClibc) , dan butuh waktu bertahun-tahun sebelum implementasi ruang pengguna NPTL dari GNU LibC porting dan diasumsikan sebagai implementasi threading POSIX default, seperti umumnya platform khusus ini tidak berusaha untuk mengikuti mode terbaru dengan kecepatan kilat. Ini dapat diamati dengan memperhatikan bahwa memang PID untuk utas yang berbeda pada platform tersebut juga berbeda dengan standar POSIX - seperti buku yang Anda baca menjelaskan. Sebenarnya begitu Anda menelepon
pthread_create()
, Anda tiba-tiba meningkatkan hitungan proses dari satu menjadi tiga karena proses tambahan diperlukan untuk menjaga kekacauan tetap sama.Halaman manual Linux pthreads (7) memberikan gambaran yang komprehensif dan menarik dari perbedaan keduanya. Deskripsi lain yang mencerahkan, meskipun ketinggalan zaman, perbedaannya adalah makalah ini oleh Ulrich Depper dan Ingo Molnar tentang desain NPTL.
Saya sarankan Anda untuk tidak menganggap bagian buku itu terlalu serius. Saya malah merekomendasikan thread POSIX Pemrograman Butenhof dan halaman manual POSIX dan Linux tentang subjek ini. Banyak tutorial tentang masalah ini tidak akurat.
sumber
Utas (Userspace) tidak diimplementasikan sebagai proses seperti pada Linux, dalam hal bahwa mereka tidak memiliki ruang alamat pribadi mereka sendiri, mereka masih berbagi ruang alamat dari proses induk.
Namun, utas ini diterapkan untuk menggunakan sistem akuntansi proses kernel, jadi dialokasikan ID Utas sendiri (TID), tetapi diberi PID dan 'ID grup utas' (TGID) yang sama dengan proses induk - ini berbeda dengan garpu, tempat TGID dan PID baru dibuat, dan TID sama dengan PID.
Jadi tampaknya kernel baru-baru ini memiliki TID terpisah yang dapat ditanyakan, apakah ini yang berbeda untuk utas, cuplikan kode yang sesuai untuk menunjukkan ini di masing-masing utama () thread_function () di atas adalah:
Jadi seluruh kode dengan ini adalah:
Memberikan contoh output dari:
sumber
Pada dasarnya, informasi dalam buku Anda secara historis akurat, karena sejarah implementasi utas yang sangat buruk di Linux. Jawaban saya atas pertanyaan terkait pada SO juga berfungsi sebagai jawaban untuk pertanyaan Anda:
https://stackoverflow.com/questions/9154671/distinction-between-processes-and-threads-in-linux/9154725#9154725
sumber
Secara internal, tidak ada yang namanya proses atau utas di kernel linux. Proses dan utas sebagian besar adalah konsep userland, kernel itu sendiri hanya melihat "tugas", yang merupakan objek terjadwal yang mungkin tidak berbagi, sebagian, atau semua sumber dayanya dengan tugas lain. Utas adalah tugas yang telah dikonfigurasikan untuk membagikan sebagian besar sumber dayanya (ruang alamat, mmaps, pipa, penangan file terbuka, soket, dll.) Dengan tugas induk, dan proses adalah tugas yang telah dikonfigurasikan untuk berbagi sumber daya minimal dengan tugas induk .
Saat Anda menggunakan Linux API secara langsung ( clone () , alih-alih fork () dan pthread_create () ), maka Anda memiliki lebih banyak fleksibilitas dalam menentukan berapa banyak sumber daya untuk dibagikan atau tidak dibagikan, dan Anda dapat membuat tugas yang tidak sepenuhnya memproses atau sepenuhnya thread. Jika Anda menggunakan panggilan tingkat rendah ini secara langsung, dimungkinkan juga untuk membuat tugas dengan TGID baru (dengan demikian diperlakukan sebagai proses oleh sebagian besar alat pengguna lahan) yang benar-benar membagikan semua sumber dayanya dengan tugas induk, atau sebaliknya, untuk membuat tugas dengan TGID yang dibagikan (dengan demikian diperlakukan sebagai utas oleh sebagian besar alat pengguna tanah) yang tidak berbagi sumber daya dengan tugas induknya.
Sementara Linux 2.4 mengimplementasikan TGID, ini sebagian besar hanya untuk kepentingan akuntansi sumber daya. Banyak pengguna dan alat userspace merasa berguna untuk dapat mengelompokkan tugas-tugas terkait bersama dan melaporkan penggunaan sumber daya mereka bersama-sama.
Implementasi tugas di Linux jauh lebih lancar daripada proses dan benang pandangan dunia yang disajikan oleh alat userspace.
sumber
Linus Torvalds menyatakan dalam sebuah mailing list kernel pada tahun 1996 bahwa "baik utas maupun proses diperlakukan sebagai 'konteks eksekusi'", yang merupakan "hanya konglomerat dari semua keadaan CoE itu .... termasuk hal-hal seperti CPU status, status MMU, izin, dan berbagai status komunikasi (file terbuka, penangan sinyal, dll) ".
Seperti yang Anda lihat program ini akan menelurkan 25 utas sekaligus, masing-masing akan tidur selama 100 detik dan kemudian bergabung dengan program utama lagi. Setelah semua 25 utas bergabung kembali dengan program, program selesai dan akan keluar.
Menggunakan
top
Anda akan dapat melihat 25 contoh program "threads2". Tapi kidna membosankan. Output darips auwx
bahkan kurang menarik ... TAPIps -eLf
mendapat agak menarik.Anda dapat melihat di sini ke-26 CoEr bahwa
thread2
program telah dibuat. Mereka semua berbagi ID proses (PID) yang sama dan ID proses induk (PPID) tetapi masing-masing memiliki ID LWP yang berbeda (proses ringan), dan jumlah LWP (NLWP) menunjukkan ada 26 CoE - program utama dan 25 utas melahirkannya.sumber
Ketika datang ke proses Linux dan utas adalah jenis hal yang sama. Yang mengatakan mereka diciptakan dengan system call yang sama:
clone
.Jika Anda memikirkannya, perbedaan antara utas dan proses adalah di mana objek kernel akan dibagikan oleh anak dan orang tua. Untuk proses, itu tidak banyak: deskriptor file terbuka, segmen memori yang belum ditulis, mungkin beberapa lainnya yang saya tidak bisa memikirkan dari atas kepala saya. Untuk utas, lebih banyak objek dibagikan, tetapi tidak semua.
Apa yang membuat utas dan objek lebih dekat di Linux adalah
unshare
panggilan sistem. Objek kernel yang mulai dibagikan dapat dibagikan setelah pembuatan utas. Jadi, Anda dapat, misalnya, memiliki dua utas dari proses yang sama yang memiliki ruang deskriptor file yang berbeda (dengan mencabut pembagian deskriptor file setelah utas dibuat). Anda dapat mengujinya sendiri dengan membuat utas, memanggilunshare
kedua utas dan kemudian menutup semua file dan membuka file baru, pipa atau objek di kedua utas tersebut. Kemudian lihat ke dalam/proc/your_proc_fd/task/*/fd
dan Anda akan melihat bahwa masing-masingtask
(yang Anda buat sebagai utas) akan memiliki fd yang berbeda.Faktanya, baik pembuatan utas baru maupun proses baru adalah rutinitas pustaka yang memanggil di
clone
bawahnya dan menentukan objek kernel mana yangtask
akan dibagikan oleh proses-thread-thingamajig (yaitu, ) dengan proses pemanggilan / utas.sumber