Sumber daya apa yang dibagi di antara utas?

264

Baru-baru ini, saya telah ditanya pertanyaan dalam wawancara apa perbedaan antara proses dan utas. Sungguh, saya tidak tahu jawabannya. Saya berpikir sejenak dan memberikan jawaban yang sangat aneh.

Thread berbagi memori yang sama, proses tidak. Setelah menjawab ini, pewawancara memberi saya senyum jahat dan mengajukan pertanyaan berikut kepada saya:

P. Apakah Anda tahu segmen di mana suatu program dibagi?

Jawaban saya: ya (pikir itu mudah) Stack, Data, Code, Heap

Q. Jadi, beri tahu saya: segmen mana yang dibagikan thread?

Saya tidak bisa menjawab ini dan akhirnya mengatakan semuanya.

Tolong, bisakah ada yang menyajikan jawaban yang benar dan mengesankan untuk perbedaan antara proses dan utas?

Xinus
sumber
9
Thread berbagi ruang alamat virtual yang sama , proses tidak.
Benoit
2
mungkin duplikat Apa perbedaan antara suatu proses dan thread
sashoalm

Jawaban:

177

Anda benar, tetapi utas membagikan semua segmen kecuali tumpukan. Utas memiliki susunan panggilan independen, namun memori di susunan utas lainnya masih dapat diakses dan secara teori Anda dapat menahan pointer ke memori dalam kerangka tumpukan lokal beberapa utas lainnya (meskipun Anda mungkin harus menemukan tempat yang lebih baik untuk meletakkan memori itu!).

Greg Hewgill
sumber
27
Bagian yang menarik adalah bahwa meskipun utas memiliki tumpukan panggilan independen, memori di tumpukan lainnya masih dapat diakses.
Karthik Balaguru
1
ya - saya ingin tahu apakah dapat mengakses memori di tumpukan lain di antara utas? Selama Anda yakin Anda tidak mencoba mereferensikan tumpukan yang telah dibatalkan alokasi, saya tidak yakin saya melihat masalah dengan itu?
bph
2
@ bb: Ini mungkin untuk mengakses memori tumpukan thread lain, tetapi untuk kepentingan praktik rekayasa perangkat lunak yang baik, saya tidak akan mengatakan itu dapat diterima untuk melakukannya.
Greg Hewgill
1
Mengakses, terutama menulis, tumpukan thread lain mengacaukan beberapa implementasi pengumpul sampah. Ini bisa dibenarkan sebagai kesalahan implementasi GC.
yyny
56

Dari Wikipedia (saya pikir itu akan menjadi jawaban yang sangat bagus untuk pewawancara: P)

Utas berbeda dari proses sistem operasi multitasking tradisional dalam hal:

  • proses biasanya independen, sementara utas ada sebagai himpunan bagian dari suatu proses
  • proses membawa informasi keadaan yang cukup, sedangkan banyak utas dalam keadaan berbagi proses serta memori dan sumber daya lainnya
  • proses memiliki ruang alamat yang terpisah, sedangkan utas berbagi ruang alamat mereka
  • proses berinteraksi hanya melalui mekanisme komunikasi antar proses yang disediakan sistem.
  • Pergantian konteks antar utas dalam proses yang sama biasanya lebih cepat daripada pergantian konteks antar proses.
Jorge Córdoba
sumber
2
tentang poin no 2 di atas: Untuk utas juga CPU mempertahankan konteks.
Jack
49

Sesuatu yang benar-benar perlu ditunjukkan adalah bahwa sebenarnya ada dua aspek untuk pertanyaan ini - aspek teoritis dan aspek implementasi.

Pertama, mari kita lihat aspek teoretisnya. Anda perlu memahami apa proses secara konseptual untuk memahami perbedaan antara proses dan utas dan apa yang dibagikan di antara mereka.

Kami memiliki yang berikut dari bagian 2.2.2 Model Thread Klasik dalam Sistem Operasi Modern 3e oleh Tanenbaum:

Model proses didasarkan pada dua konsep independen: pengelompokan sumber daya dan eksekusi. Terkadang berguna untuk memisahkan mereka; Di sinilah utas masuk ....

Dia melanjutkan:

Salah satu cara memandang suatu proses adalah cara mengelompokkan sumber daya terkait. Suatu proses memiliki ruang alamat yang berisi teks dan data program, serta sumber daya lainnya. Sumber daya ini dapat mencakup file terbuka, proses anak, alarm yang tertunda, penangan sinyal, informasi akuntansi, dan banyak lagi. Dengan menyatukan mereka dalam bentuk proses, mereka dapat dikelola dengan lebih mudah. Konsep lain yang dimiliki suatu proses adalah utas eksekusi, biasanya disingkat menjadi hanya utas. Utas memiliki penghitung program yang melacak instruksi mana yang harus dijalankan selanjutnya. Ini memiliki register, yang menyimpan variabel kerja saat ini. Ini memiliki tumpukan, yang berisi riwayat eksekusi, dengan satu frame untuk setiap prosedur yang dipanggil tetapi belum kembali dari. Meskipun utas harus dijalankan dalam beberapa proses, utas dan prosesnya adalah konsep yang berbeda dan dapat diperlakukan secara terpisah. Proses digunakan untuk mengelompokkan sumber daya bersama; utas adalah entitas yang dijadwalkan untuk dieksekusi pada CPU.

Lebih jauh ke bawah ia menyediakan tabel berikut:

Per process items             | Per thread items
------------------------------|-----------------
Address space                 | Program counter
Global variables              | Registers
Open files                    | Stack
Child processes               | State
Pending alarms                |
Signals and signal handlers   |
Accounting information        |

Di atas adalah apa yang Anda butuhkan agar thread dapat berfungsi. Seperti yang telah ditunjukkan orang lain, hal-hal seperti segmen adalah detail implementasi tergantung OS.

Robert S. Barnes
sumber
2
Ini penjelasan yang bagus. Tapi itu mungkin harus diikat kembali ke pertanyaan entah bagaimana untuk dianggap sebagai "Jawaban"
catalyst294
Berkenaan dengan tabel, bukankah program counter register? dan "negara" dari sebuah utas, ditangkap dalam nilai register? Saya juga kehilangan pointer ke kode yang mereka jalankan (pointer ke teks proses)
onlycparra
29

Beri tahu pewawancara bahwa itu sepenuhnya tergantung pada implementasi OS.

Ambil Windows x86 misalnya. Hanya ada 2 segmen [1], Kode dan Data. Dan keduanya dipetakan ke seluruh ruang alamat 2GB (linier, pengguna). Basis = 0, Batas = 2GB. Mereka akan membuat satu tetapi x86 tidak memungkinkan segmen menjadi Baca / Tulis dan Jalankan. Jadi mereka membuat dua, dan mengatur CS untuk menunjuk ke deskriptor kode, dan sisanya (DS, ES, SS, dll) untuk menunjuk ke yang lain [2]. Namun keduanya menunjuk ke hal yang sama!

Orang yang mewawancarai Anda telah membuat asumsi tersembunyi bahwa ia tidak menyatakannya, dan itu adalah trik bodoh untuk ditarik.

Jadi tentang

P. Jadi, beri tahu saya segmen mana yang dibagikan?

Segmen tidak relevan dengan pertanyaan, setidaknya di Windows. Utas berbagi seluruh ruang alamat. Hanya ada 1 tumpukan segmen, SS, dan itu menunjuk ke hal-hal yang sama persis seperti yang dilakukan DS, ES, dan CS [2]. Yaitu seluruh ruang pengguna berdarah . 0-2GB. Tentu saja, itu tidak berarti utas hanya memiliki 1 tumpukan. Biasanya masing-masing memiliki tumpukan sendiri, tetapi segmen x86 tidak digunakan untuk tujuan ini.

Mungkin * nix melakukan sesuatu yang berbeda. Siapa tahu. Premis yang mendasari pertanyaan itu rusak.


  1. Setidaknya untuk ruang pengguna.
  2. Dari ntsd notepad:cs=001b ss=0023 ds=0023 es=0023
Alex Budovski
sumber
1
Yap ... Segmen tergantung pada OS dan kompiler / penghubung. Terkadang ada segmen BSS yang terpisah dari segmen DATA. Terkadang ada RODATA (Data seperti string konstan yang dapat di halaman yang ditandai Hanya Baca). Beberapa sistem bahkan memecah DATA menjadi DATA KECIL (dapat diakses dari basis + offset 16-bit) dan DATA (JAUH) (diperlukan offset 32-bit untuk mengakses). Ada juga kemungkinan bahwa ada Segmen TLS DATA (Utang Toko Lokal) ekstra yang dihasilkan berdasarkan per-utas
Adisak
5
Ah tidak! Anda membingungkan segmen dengan bagian! Bagian adalah bagaimana tautan membagi modul menjadi beberapa bagian (data, rdata, teks, bss, dll.) Seperti yang Anda gambarkan. Tapi saya berbicara tentang segmen, sebagaimana ditentukan dalam perangkat keras intel / amd x86. Sama sekali tidak terkait dengan kompiler / penghubung. Harapan itu masuk akal.
Alex Budovski
Namun, Adisak benar tentang toko Thread Lokal. Ini pribadi untuk utas dan tidak dibagikan. Saya mengetahui OS Windows dan tidak yakin dengan OS lain.
Jack
20

Secara umum, Thread disebut proses ringan. Jika kita membagi memori menjadi tiga bagian maka akan menjadi: Kode, data, dan Stack. Setiap proses memiliki bagian kode, data, dan tumpukan sendiri dan karena konteks ini, waktu sakelar agak tinggi. Untuk mengurangi waktu switching konteks, orang telah datang dengan konsep utas, yang membagi data dan segmen kode dengan utas / proses lain dan memiliki segmen STACK sendiri.

Nimish Thakkar
sumber
Anda lupa tumpukan. Heap, jika saya tidak salah, harus dibagikan di antara utas
Phate
20

Suatu proses memiliki kode, data, tumpukan dan tumpukan segmen. Sekarang, Instruction Pointer (IP) dari utas atau utas menunjuk ke segmen kode dari proses. Segmen data dan tumpukan dibagi oleh semua utas. Sekarang bagaimana dengan area stack? Apa sebenarnya area tumpukan? Ini adalah area yang dibuat oleh proses hanya untuk menggunakan utasnya ... karena tumpukan dapat digunakan dengan cara yang jauh lebih cepat daripada tumpukan dll. Area tumpukan proses dibagi di antara utas, yaitu jika ada 3 utas, maka tumpukan area dari proses dibagi menjadi 3 bagian dan masing-masing diberikan kepada 3 utas. Dengan kata lain, ketika kita mengatakan bahwa setiap utas memiliki tumpukan sendiri, tumpukan itu sebenarnya merupakan bagian dari area tumpukan proses yang dialokasikan untuk setiap utas. Ketika sebuah utas menyelesaikan eksekusi, tumpukan utas tersebut direklamasi oleh proses. Faktanya, tidak hanya tumpukan proses yang dibagi di antara utas, tetapi semua set register yang menggunakan thread seperti SP, PC dan register negara adalah register dari proses. Jadi ketika harus berbagi, kode, data, dan area tumpukan dibagi, sedangkan area tumpukan hanya dibagi di antara utas.

Dhirendra Vikash Sharma
sumber
13

Thread berbagi kode dan segmen data dan heap, tetapi mereka tidak membagikan stack.

Kevin Peterson
sumber
11
Ada perbedaan antara "dapat mengakses data di tumpukan" dan berbagi tumpukan. Utas-utas itu memiliki tumpukan mereka sendiri yang didorong dan muncul ketika mereka memanggil metode.
Kevin Peterson
2
Keduanya sama-sama pandangan yang valid. Ya, setiap utas memiliki tumpukan sendiri dalam arti bahwa ada korespondensi satu-ke-satu antara utas dan tumpukan dan setiap utas memiliki ruang yang digunakannya untuk penggunaan tumpukan normal sendiri. Tetapi mereka juga sepenuhnya berbagi sumber daya proses dan jika diinginkan, utas apa pun dapat mengakses tumpukan utas lainnya semudah miliknya.
David Schwartz
@ DavidvidSchwartz, dapatkah saya meringkas poin Anda seperti di bawah ini: Setiap utas memiliki tumpukan sendiri, dan tumpukan terdiri dari 2 bagian - bagian pertama yang dibagi di antara utas sebelum prosesnya adalah multi-utas, dan bagian kedua yang diisi saat utas pemiliknya berjalan .. Setuju?
FaceBro
2
@nextTide Tidak ada dua bagian. Tumpukan dibagi, titik. Setiap utas memiliki tumpukan sendiri, tetapi mereka juga dibagikan. Mungkin analogi yang baik adalah jika Anda dan istri Anda masing-masing memiliki mobil tetapi Anda dapat menggunakan mobil satu sama lain kapan saja Anda mau.
David Schwartz
5

Thread berbagi data dan kode sementara proses tidak. Tumpukan tidak dibagi untuk keduanya.

Proses juga dapat berbagi memori, lebih tepatnya kode, misalnya setelah a Fork(), tetapi ini adalah detail implementasi dan (sistem operasi) optimasi. Kode yang dibagikan oleh banyak proses akan (mudah-mudahan) menjadi duplikat pada penulisan pertama ke kode - ini dikenal sebagai copy-on-write . Saya tidak yakin tentang semantik yang tepat untuk kode utas, tetapi saya menganggap kode yang dibagikan.

           Utas proses

   Susun pribadi pribadi
   Data pribadi dibagikan
   Kode pribadi 1   dibagikan 2

1 Kode ini secara logis pribadi tetapi mungkin bersama untuk alasan kinerja. 2 Saya tidak yakin 100%.

Daniel Brückner
sumber
Saya akan mengatakan segmen kode (segmen teks), tidak seperti data, hampir selalu dibaca hanya pada sebagian besar arsitektur.
Jorge Córdoba
4

Threads membagikan semuanya [1]. Ada satu ruang alamat untuk seluruh proses.

Setiap utas memiliki tumpukan dan registernya sendiri, tetapi semua tumpukan utas terlihat di ruang alamat bersama.

Jika satu utas mengalokasikan beberapa objek pada tumpukannya, dan mengirimkan alamat ke utas lain, keduanya akan memiliki akses yang sama ke objek tersebut.


Sebenarnya, saya baru saja memperhatikan masalah yang lebih luas: Saya pikir Anda membingungkan dua penggunaan segmen kata .

Format file untuk yang dapat dieksekusi (mis., ELF) memiliki bagian yang berbeda di dalamnya, yang dapat disebut sebagai segmen, yang berisi kode kompilasi (teks), data yang diinisialisasi, simbol tautan, info debug, dll. Tidak ada segmen tumpukan atau tumpukan di sini, karena itu hanya konstruksi runtime.

Segmen file biner ini dapat dipetakan ke dalam ruang alamat proses secara terpisah, dengan izin yang berbeda (mis. Read-only executable untuk kode / teks, dan copy-on-write yang tidak dapat dieksekusi untuk data yang diinisialisasi).

Area ruang alamat ini digunakan untuk tujuan yang berbeda, seperti alokasi tumpukan dan tumpukan utas, berdasarkan konvensi (diberlakukan oleh pustaka runtime bahasa Anda). Itu semua hanya memori, dan mungkin tidak tersegmentasi kecuali Anda menjalankan dalam mode 8086 virtual. Setiap tumpukan thread adalah sepotong memori yang dialokasikan pada waktu pembuatan thread, dengan alamat top stack saat ini disimpan dalam register penunjuk tumpukan, dan setiap utas menyimpan penunjuk tumpukannya sendiri bersama dengan register lainnya.


[1] OK, saya tahu: masker sinyal, TSS / TSD dll. Ruang alamat, termasuk semua segmen program yang dipetakan, masih dibagikan.

Tak berguna
sumber
3

Dalam kerangka kerja x86, seseorang dapat membagi banyak segmen (hingga 2 ^ 16-1). Arahan ASM SEGMENT / ENDS memungkinkan ini, dan operator SEG dan OFFSET memungkinkan inisialisasi register segmen. CS: IP biasanya diinisialisasi oleh loader, tetapi untuk DS, ES, SS aplikasi bertanggung jawab dengan inisialisasi. Banyak lingkungan memungkinkan apa yang disebut "definisi segmen yang disederhanakan" seperti .code, .data, .bss, .stack dll. Dan, tergantung juga pada "model memori" (kecil, besar, padat dll.) Loader memulai register segmen demikian. Biasanya .data, .bss, .stack, dan segmen biasa lainnya (saya belum melakukan ini sejak 20 tahun jadi saya tidak ingat semua) dikelompokkan dalam satu kelompok tunggal - itulah sebabnya biasanya DS, ES dan SS menunjuk ke area yang sama, tetapi ini hanya untuk menyederhanakan hal-hal.

Secara umum, semua register segmen dapat memiliki nilai yang berbeda saat dijalankan. Jadi, pertanyaan wawancara itu benar: yang mana dari KODE, DATA, dan STACK yang dibagikan di antara utas. Manajemen heap adalah sesuatu yang lain - itu hanya urutan panggilan ke OS. Tetapi bagaimana jika Anda tidak memiliki OS sama sekali, seperti dalam sistem tertanam - dapatkah Anda masih memiliki / menghapus baru dalam kode Anda?

Saran saya kepada orang-orang muda - baca beberapa buku pemrograman perakitan yang bagus. Tampaknya kurikulum universitas sangat buruk dalam hal ini.

George
sumber
2

Selain memori global, utas juga berbagi sejumlah atribut lainnya (yaitu, atribut ini bersifat global untuk suatu proses, bukan khusus untuk utas). Atribut-atribut ini meliputi:

  • ID proses dan ID proses induk;
  • ID grup proses dan ID sesi;
  • terminal pengendali;
  • kredensial proses (ID pengguna dan grup);
  • buka deskriptor file;
  • rekam kunci yang dibuat menggunakan fcntl();
  • disposisi sinyal;
  • informasi terkait sistem file: umask, direktori kerja saat ini, dan direktori root;
  • timer interval ( setitimer()) dan timer POSIX ( timer_create());
  • Nilai sistem V semaphore undo ( semadj) (Bagian 47.8);
  • batas sumber daya;
  • Waktu CPU dikonsumsi (seperti yang dikembalikan oleh times());
  • sumber daya yang dikonsumsi (seperti yang dikembalikan oleh getrusage()); dan
  • nilai bagus (ditetapkan oleh setpriority()dan nice()).

Di antara atribut yang berbeda untuk setiap utas adalah yang berikut:

  • ID utas (Bagian 29.5);
  • topeng sinyal;
  • data khusus utas (Bagian 31.3);
  • tumpukan sinyal alternatif ( sigaltstack());
  • variabel errno;
  • lingkungan titik-mengambang (lihat fenv(3));
  • kebijakan dan prioritas penjadwalan realtime (Bagian 35.2 dan 35.3);
  • Afinitas CPU (spesifik Linux, dijelaskan dalam Bagian 35.4);
  • kemampuan (khusus Linux, dijelaskan pada Bab 39); dan
  • stack (variabel lokal dan informasi keterkaitan fungsi panggilan).

Kutipan dari: Antarmuka Pemrograman Linux: Buku Pegangan Pemrograman Sistem Linux dan UNIX, Michael Kerrisk , halaman 619

snr
sumber
0

Thread berbagi heap (ada penelitian tentang heap spesifik thread) tetapi implementasi saat ini berbagi heap. (dan tentu saja kodenya)

Dani
sumber
0

Dalam prosesnya, semua utas berbagi sumber daya sistem seperti memori tumpukan dll. Sementara utas memiliki tumpukan sendiri

Jadi ans Anda harus menumpuk memori yang berbagi semua utas untuk suatu proses.

roshni
sumber