Tài nguyên nào được chia sẻ giữa các chủ đề?


264

Gần đây, tôi đã được hỏi một câu hỏi trong một cuộc phỏng vấn về sự khác biệt giữa một quy trình và một chủ đề. Thực sự, tôi không biết câu trả lời. Tôi suy nghĩ một phút và đưa ra một câu trả lời rất kỳ lạ.

Chủ đề chia sẻ cùng một bộ nhớ, quá trình không. Sau khi trả lời, người phỏng vấn nở một nụ cười xấu xa và bắn những câu hỏi sau vào tôi:

Q. Bạn có biết các phân đoạn mà một chương trình được chia không?

Câu trả lời của tôi: yep (nghĩ rằng đó là một cách dễ dàng) Stack, Data, Code, Heap

Q. Vì vậy, hãy cho tôi biết: phân khúc nào chủ đề chia sẻ?

Tôi không thể trả lời điều này và cuối cùng đã nói tất cả.

Xin vui lòng, bất cứ ai có thể trình bày các câu trả lời chính xác và ấn tượng cho sự khác biệt giữa một quá trình và một chủ đề?


9
Chủ đề chia sẻ cùng một không gian địa chỉ ảo , quá trình không.
Benoit

Câu trả lời:


177

Bạn khá chính xác, nhưng các chủ đề chia sẻ tất cả các phân đoạn ngoại trừ ngăn xếp. Các luồng có ngăn xếp cuộc gọi độc lập, tuy nhiên bộ nhớ trong các ngăn xếp luồng khác vẫn có thể truy cập được và theo lý thuyết bạn có thể giữ một con trỏ tới bộ nhớ trong khung ngăn xếp cục bộ của một số luồng khác (mặc dù bạn có thể nên tìm một nơi tốt hơn để đặt bộ nhớ đó!).


27
Phần thú vị là mặc dù các luồng có ngăn xếp cuộc gọi độc lập, bộ nhớ trong các ngăn xếp khác vẫn có thể truy cập được.
Karthik Balaguru

1
có - tôi đang tự hỏi liệu có thể chấp nhận truy cập bộ nhớ trong các ngăn xếp khác giữa các luồng không? Miễn là bạn chắc chắn rằng bạn không cố gắng tham chiếu một ngăn xếp đã bị hủy bỏ Tôi không chắc chắn tôi thấy có vấn đề với nó?
bph

2
@bph: Có thể truy cập bộ nhớ ngăn xếp của một luồng khác, nhưng vì lợi ích của thực hành kỹ thuật phần mềm tốt, tôi sẽ không nói rằng có thể chấp nhận làm như vậy.
Greg Hewgill

1
Truy cập, đặc biệt là viết vào, các ngăn xếp của các luồng khác gây rối với một số triển khai trình thu gom rác. Điều này có thể được coi là một lỗi của việc thực hiện GC, mặc dù.
yyny

56

Từ Wikipedia (Tôi nghĩ rằng điều đó sẽ tạo ra một câu trả lời thực sự tốt cho người phỏng vấn: P)

Chủ đề khác với các quy trình hệ điều hành đa nhiệm truyền thống ở chỗ:

  • các quy trình thường độc lập, trong khi các chủ đề tồn tại dưới dạng tập hợp con của một quy trình
  • các quy trình mang thông tin trạng thái đáng kể, trong khi nhiều luồng trong trạng thái chia sẻ quy trình cũng như bộ nhớ và các tài nguyên khác
  • các quy trình có không gian địa chỉ riêng biệt, trong khi các luồng chia sẻ không gian địa chỉ của chúng
  • các quy trình chỉ tương tác thông qua các cơ chế truyền thông liên quy trình do hệ thống cung cấp.
  • Chuyển đổi ngữ cảnh giữa các luồng trong cùng một quy trình thường nhanh hơn chuyển ngữ cảnh giữa các tiến trình.

2
about point no 2 ở trên: Đối với các chủ đề, CPU cũng duy trì một bối cảnh.
Jack

49

Một cái gì đó thực sự cần phải được chỉ ra là thực sự có hai khía cạnh cho câu hỏi này - khía cạnh lý thuyết và khía cạnh thực hiện.

Đầu tiên, chúng ta hãy nhìn vào khía cạnh lý thuyết. Bạn cần hiểu một quy trình là gì về mặt khái niệm để hiểu sự khác biệt giữa một quy trình và một chủ đề và những gì được chia sẻ giữa chúng.

Chúng tôi có phần sau đây từ phần 2.2.2 Mô hình chủ đề cổ điển trong các hệ điều hành hiện đại 3e của Tanenbaum:

Mô hình quy trình dựa trên hai khái niệm độc lập: nhóm tài nguyên và thực thi. Đôi khi nó rất hữu ích để tách chúng ra; đây là nơi các chủ đề đến ....

Ông tiếp tục:

Một cách để xem xét một quy trình là đó là một cách để nhóm các tài nguyên liên quan lại với nhau. Một quy trình có một không gian địa chỉ chứa văn bản và dữ liệu chương trình, cũng như các tài nguyên khác. Các tài nguyên này có thể bao gồm các tệp đang mở, các quy trình con, báo động đang chờ xử lý, xử lý tín hiệu, thông tin kế toán, v.v. Bằng cách đặt chúng lại với nhau dưới dạng một quy trình, chúng có thể được quản lý dễ dàng hơn. Khái niệm khác mà một quá trình có là một luồng thực thi, thường được rút ngắn thành chỉ luồng. Các chủ đề có một bộ đếm chương trình theo dõi hướng dẫn nào để thực hiện tiếp theo. Nó có các thanh ghi, giữ các biến làm việc hiện tại của nó. Nó có một ngăn xếp, chứa lịch sử thực hiện, với một khung cho mỗi thủ tục được gọi nhưng chưa được trả về. Mặc dù một luồng phải thực thi trong một số quy trình, luồng và quá trình của nó là các khái niệm khác nhau và có thể được xử lý riêng. Các quy trình được sử dụng để nhóm các tài nguyên với nhau; luồng là các thực thể được lên lịch để thực hiện trên CPU.

Hơn nữa, ông cung cấp bảng sau:

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        |

Trên đây là những gì bạn cần cho chủ đề để làm việc. Như những người khác đã chỉ ra, những thứ như phân khúc là chi tiết triển khai phụ thuộc hệ điều hành.


2
Đây là một lời giải thích tuyệt vời. Nhưng có lẽ nó nên được gắn lại với câu hỏi bằng cách nào đó để được coi là "Trả lời"
chất xúc

Liên quan đến bảng, không phải là chương trình truy cập một đăng ký? và "trạng thái" của một luồng, được ghi trong giá trị của các thanh ghi? Tôi cũng thiếu con trỏ tới mã mà họ chạy (con trỏ tới văn bản xử lý)
onlycparra

29

Nói với người phỏng vấn rằng nó phụ thuộc hoàn toàn vào việc triển khai HĐH.

Lấy Windows x86 làm ví dụ. Chỉ có 2 phân đoạn [1], Mã và Dữ liệu. Và cả hai đều được ánh xạ tới toàn bộ không gian địa chỉ 2GB (tuyến tính, người dùng). Cơ sở = 0, Giới hạn = 2GB. Họ đã tạo một nhưng x86 không cho phép một phân đoạn vừa đọc / ghi và thực thi. Vì vậy, họ đã tạo hai và đặt CS để trỏ đến bộ mô tả mã và phần còn lại (DS, ES, SS, v.v.) để trỏ đến cái khác [2]. Nhưng cả hai đều chỉ đến cùng một thứ!

Người phỏng vấn bạn đã đưa ra một giả định ẩn rằng anh ấy / cô ấy không nói rõ, và đó là một mánh khóe ngu ngốc để kéo.

Liên quan

Q. Vì vậy, cho tôi biết chia sẻ chủ đề phân khúc?

Các phân đoạn không liên quan đến câu hỏi, ít nhất là trên Windows. Chủ đề chia sẻ toàn bộ không gian địa chỉ. Chỉ có 1 phân đoạn ngăn xếp, SS và nó trỏ đến cùng một thứ chính xác mà DS, ES và CS thực hiện [2]. Tức là toàn bộ không gian người dùng đẫm máu . 0-2GB. Tất nhiên, điều đó không có nghĩa là các chủ đề chỉ có 1 ngăn xếp. Đương nhiên mỗi cái có ngăn xếp riêng, nhưng các phân đoạn x86 không được sử dụng cho mục đích này.

Có lẽ * nix làm điều gì đó khác biệt. Ai biết. Tiền đề của câu hỏi dựa trên đã bị phá vỡ.


  1. Ít nhất là cho không gian người dùng.
  2. Từ ntsd notepad:cs=001b ss=0023 ds=0023 es=0023

1
Đúng ... Phân đoạn phụ thuộc vào HĐH và trình biên dịch / liên kết. Đôi khi có một phân đoạn BSS riêng biệt từ phân đoạn DATA. Đôi khi có RODATA (Dữ liệu như các chuỗi không đổi có thể ở các trang được đánh dấu Chỉ đọc). Một số hệ thống thậm chí chia DATA thành DỮ LIỆU NHỎ (có thể truy cập từ cơ sở + offset 16 bit) và (FAR) DATA (yêu cầu bù 32 bit để truy cập). Cũng có thể có thêm Phân đoạn TLS DATA (Cửa hàng cục bộ) được tạo trên cơ sở từng luồng
Adisak

5
À không! Bạn đang phân khúc khó hiểu với các phần! Các phần là cách trình liên kết chia mô-đun thành các phần (dữ liệu, dữ liệu, văn bản, bss, v.v.) như bạn mô tả. Nhưng tôi đang nói về các phân đoạn, như được chỉ định trong phần cứng intel / amd x86. Không liên quan đến tất cả các trình biên dịch / liên kết. Hy vọng rằng có ý nghĩa.
Alex Budovski

Tuy nhiên, Adisak nói đúng về cửa hàng Thread Local. Nó là riêng tư cho chủ đề và không được chia sẻ. Tôi biết về HĐH Windows và không chắc chắn về HĐH khác.
Jack

20

Nói chung, Chủ đề được gọi là quá trình trọng lượng nhẹ. Nếu chúng ta chia bộ nhớ thành ba phần thì đó sẽ là: Mã, dữ liệu và Stack. Mỗi quá trình có phần mã, dữ liệu và ngăn xếp riêng và do thời gian chuyển đổi ngữ cảnh này hơi cao. Để giảm thời gian chuyển ngữ cảnh, mọi người đã đưa ra khái niệm về luồng, chia sẻ phân đoạn Dữ liệu và mã với luồng / quy trình khác và nó có phân đoạn STACK riêng.


Bạn quên đống. Heap, nếu tôi không sai, nên được chia sẻ giữa các chủ đề
Phate

20

Một quy trình có các đoạn mã, dữ liệu, đống và ngăn xếp. Bây giờ, Con trỏ lệnh (IP) của một luồng HOẶC các luồng trỏ đến đoạn mã của quy trình. Các phân đoạn dữ liệu và heap được chia sẻ bởi tất cả các luồng. Bây giờ những gì về khu vực ngăn xếp? Khu vực ngăn xếp thực sự là gì? Đó là một khu vực được tạo bởi quy trình chỉ để sử dụng luồng của nó ... bởi vì các ngăn xếp có thể được sử dụng theo cách nhanh hơn nhiều so với đống, v.v. Vùng ngăn xếp của quy trình được chia cho các luồng, tức là nếu có 3 luồng, thì diện tích ngăn xếp của quá trình được chia thành 3 phần và mỗi phần được trao cho 3 luồng. Nói cách khác, khi chúng ta nói rằng mỗi luồng có ngăn xếp riêng, thì ngăn xếp đó thực sự là một phần của khu vực ngăn xếp quy trình được phân bổ cho mỗi luồng. Khi một luồng kết thúc thực hiện nó, ngăn xếp của luồng được thu hồi theo quy trình. Trong thực tế, không chỉ ngăn xếp của một tiến trình được chia cho các luồng, mà tất cả các tập hợp các thanh ghi mà một luồng sử dụng như SP, PC và các thanh ghi trạng thái là các thanh ghi của tiến trình. Vì vậy, khi chia sẻ, các vùng mã, dữ liệu và vùng heap được chia sẻ, trong khi vùng ngăn xếp chỉ được chia cho các luồng.


13

Chủ đề chia sẻ mã và phân đoạn dữ liệu và heap, nhưng chúng không chia sẻ ngăn xếp.


11
Có một sự khác biệt giữa "có thể truy cập dữ liệu trong ngăn xếp" và chia sẻ ngăn xếp. Những luồng này có ngăn xếp riêng của chúng được đẩy và bật lên khi chúng gọi các phương thức.
Kevin Peterson

2
Cả hai đều có quan điểm hợp lệ như nhau. Đúng, mỗi luồng có ngăn xếp riêng theo nghĩa là có sự tương ứng một-một giữa các luồng và ngăn xếp và mỗi luồng có một không gian mà nó sử dụng cho việc sử dụng ngăn xếp thông thường của riêng mình. Nhưng chúng cũng được chia sẻ đầy đủ tài nguyên quy trình và nếu muốn, bất kỳ luồng nào cũng có thể truy cập vào bất kỳ ngăn xếp nào của luồng khác dễ dàng như của chính nó.
David Schwartz

@DavidSchwartz, tôi có thể tóm tắt quan điểm của bạn như sau không: Mỗi luồng có ngăn xếp riêng và ngăn xếp gồm 2 phần - phần đầu tiên được chia sẻ giữa các luồng trước khi quá trình được đa luồng và phần thứ hai được tạo khi chủ đề sở hữu đang chạy .. Đồng ý?
FaceBro

2
@nextTide Không có hai phần. Các ngăn xếp được chia sẻ, thời gian. Mỗi luồng có ngăn xếp riêng, nhưng chúng cũng được chia sẻ. Có lẽ một điểm tương đồng tốt là nếu bạn và vợ bạn đều có một chiếc ô tô nhưng bạn có thể sử dụng xe của nhau bất cứ lúc nào bạn muốn.
David Schwartz

5

Chủ đề chia sẻ dữ liệu và mã trong khi các quá trình không. Ngăn xếp không được chia sẻ cho cả hai.

Các quy trình cũng có thể chia sẻ bộ nhớ, mã chính xác hơn, ví dụ sau một Fork(), nhưng đây là một chi tiết thực hiện và tối ưu hóa (hệ điều hành). Mã được chia sẻ bởi nhiều quá trình sẽ (hy vọng) trở thành bản sao trong lần ghi đầu tiên vào mã - điều này được gọi là sao chép trên ghi . Tôi không chắc chắn về ngữ nghĩa chính xác cho mã của các chủ đề, nhưng tôi giả sử mã được chia sẻ.

           Quá trình xử lý

   Ngăn xếp riêng tư
   Dữ liệu riêng được chia sẻ
   Mã riêng 1   chia sẻ 2

1 Mã này là hợp lý riêng nhưng có thể được chia sẻ vì lý do hiệu suất. 2 Tôi không chắc chắn 100%.


Tôi muốn nói đoạn mã (đoạn văn bản), không giống như dữ liệu, hầu như luôn luôn chỉ đọc trên hầu hết các kiến ​​trúc.
Jorge Córdoba

4

Chủ đề chia sẻ mọi thứ [1]. Có một không gian địa chỉ cho toàn bộ quá trình.

Mỗi luồng có ngăn xếp và thanh ghi riêng, nhưng tất cả các ngăn xếp của luồng đều hiển thị trong không gian địa chỉ dùng chung.

Nếu một luồng phân bổ một số đối tượng trên ngăn xếp của nó và gửi địa chỉ đến một luồng khác, cả hai sẽ có quyền truy cập như nhau vào đối tượng đó.


Trên thực tế, tôi chỉ nhận thấy một vấn đề rộng lớn hơn: Tôi nghĩ rằng bạn đang nhầm lẫn hai cách sử dụng phân đoạn từ .

Định dạng tệp cho tệp thực thi (ví dụ ELF) có các phần riêng biệt trong đó, có thể được gọi là phân đoạn, chứa mã được biên dịch (văn bản), dữ liệu khởi tạo, ký hiệu liên kết, thông tin gỡ lỗi, v.v. Không có phân đoạn heap hoặc stack ở đây, vì đó là các cấu trúc chỉ thời gian chạy.

Các phân đoạn tệp nhị phân này có thể được ánh xạ vào không gian địa chỉ quy trình một cách riêng biệt, với các quyền khác nhau (ví dụ: chỉ thực thi được đọc đối với mã / văn bản và sao chép không thể thực thi đối với dữ liệu khởi tạo).

Các khu vực của không gian địa chỉ này được sử dụng cho các mục đích khác nhau, như phân bổ heap và ngăn xếp luồng, theo quy ước (được thực thi bởi các thư viện thời gian chạy ngôn ngữ của bạn). Tất cả chỉ là bộ nhớ và có lẽ không được phân đoạn trừ khi bạn đang chạy ở chế độ 8086 ảo. Mỗi ngăn xếp của luồng là một khối bộ nhớ được phân bổ tại thời điểm tạo luồng, với địa chỉ đỉnh ngăn xếp hiện tại được lưu trữ trong một thanh ghi con trỏ ngăn xếp và mỗi luồng giữ con trỏ ngăn xếp riêng cùng với các thanh ghi khác.


[1] OK, tôi biết: mặt nạ tín hiệu, TSS / TSD, v.v. Không gian địa chỉ, bao gồm tất cả các phân đoạn chương trình được ánh xạ của nó, vẫn được chia sẻ.


3

Trong khung x86, người ta có thể chia thành nhiều phân đoạn (tối đa 2 ^ 16-1). Các chỉ thị ASM SEGMENT / ENDS cho phép điều này và các toán tử SEG và OFFSET cho phép khởi tạo các thanh ghi phân đoạn. CS: IP thường được khởi tạo bởi trình tải, nhưng đối với DS, ES, SS, ứng dụng chịu trách nhiệm khởi tạo. Nhiều môi trường cho phép cái gọi là "định nghĩa phân đoạn đơn giản hóa" như .code, .data, .bss, .stack, v.v. và tùy thuộc vào "mô hình bộ nhớ" (nhỏ, lớn, gọn, v.v.) trình tải khởi tạo các thanh ghi phân đoạn phù hợp. Thông thường .data, .bss, .stack và các phân đoạn thông thường khác (tôi đã không làm điều này từ 20 năm nên tôi không nhớ tất cả) được nhóm thành một nhóm duy nhất - đó là lý do tại sao DS, ES và SS thường chỉ đến teh Cùng một khu vực, nhưng điều này chỉ để đơn giản hóa mọi thứ.

Nói chung, tất cả các thanh ghi phân đoạn có thể có các giá trị khác nhau khi chạy. Vì vậy, câu hỏi phỏng vấn đã đúng: một trong những MÃ, DỮ LIỆU và STACK được chia sẻ giữa các luồng. Quản lý heap là một cái gì đó khác - nó chỉ đơn giản là một chuỗi các cuộc gọi đến HĐH. Nhưng điều gì sẽ xảy ra nếu bạn hoàn toàn không có HĐH, như trong một hệ thống nhúng - bạn vẫn có thể có mới / xóa trong mã của mình chứ?

Lời khuyên của tôi cho những người trẻ tuổi - đọc một số cuốn sách lập trình lắp ráp tốt. Có vẻ như các chương trình giảng dạy đại học khá kém về mặt này.


2

Bên cạnh bộ nhớ chung, các luồng cũng chia sẻ một số thuộc tính khác (nghĩa là các thuộc tính này là toàn cục đối với một quá trình, thay vì cụ thể cho một luồng). Các thuộc tính này bao gồm:

  • ID tiến trình và ID tiến trình cha mẹ;
  • ID nhóm xử lý và ID phiên;
  • thiết bị đầu cuối điều khiển;
  • quy trình thông tin đăng nhập (ID người dùng và nhóm);
  • mở mô tả tập tin;
  • khóa hồ sơ được tạo bằng cách sử dụng fcntl();
  • bố trí tín hiệu;
  • hệ thống tập tin thông tin liên quan đến mạng: umask, thư mục làm việc hiện tại và thư mục gốc;
  • bộ định thời khoảng ( setitimer()) và bộ định thời POSIX ( timer_create());
  • Giá trị hệ thống V semaphore undo ( semadj) (Mục 47.8);
  • giới hạn tài nguyên;
  • Thời gian CPU tiêu thụ (như được trả lại bởi times());
  • tài nguyên tiêu thụ (như được trả lại bởi getrusage()); và
  • giá trị tốt đẹp (được đặt bởi setpriority()nice()).

Trong số các thuộc tính riêng biệt cho từng luồng là:

  • ID luồng (Mục 29.5);
  • mặt nạ tín hiệu;
  • dữ liệu cụ thể theo luồng (Mục 31.3);
  • ngăn xếp tín hiệu thay thế ( sigaltstack());
  • biến errno;
  • môi trường điểm nổi (xem fenv(3));
  • chính sách và ưu tiên lập lịch thời gian thực (Mục 35.2 và 35.3);
  • Ái lực CPU (dành riêng cho Linux, được mô tả trong Phần 35.4);
  • các khả năng (dành riêng cho Linux, được mô tả trong Chương 39); và
  • ngăn xếp (biến cục bộ và chức năng thông tin liên kết cuộc gọi).

Trích từ: Giao diện lập trình Linux: Cẩm nang lập trình hệ thống Linux và UNIX, Michael Kerrisk , trang 619


0

Chủ đề chia sẻ heap (có một nghiên cứu về heap cụ thể chủ đề) nhưng thực hiện hiện tại chia sẻ heap. (và tất nhiên là mã)


0

Trong quá trình tất cả các luồng chia sẻ tài nguyên hệ thống như heap Memory, v.v. trong khi Thread có ngăn xếp riêng

Vì vậy, ans của bạn nên là bộ nhớ heap mà tất cả các chủ đề chia sẻ cho một quá trình.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.