Tôi không thể thêm trực tiếp vào các câu trả lời exellent do David, templatetypedef, v.v. - nếu bạn muốn tránh các chủ đề liên quan đến độ trễ và lãng phí tài nguyên, không thực hiện liên kết giữa các luồng với các vòng ngủ().
Lên lịch/gửi đi ưu tiên:
Ở cấp CPU, ngắt là chìa khóa. Hệ điều hành không làm gì cho đến khi một gián đoạn xảy ra làm cho mã của nó được nhập vào. Lưu ý rằng, trong các điều khoản OS, các ngắt có hai mùi vị - phần cứng 'thực' ngắt khiến trình điều khiển được chạy và 'ngắt phần mềm' - đây là các cuộc gọi hệ điều hành từ các luồng đã chạy có khả năng gây ra tập hợp các luồng đang chạy thay đổi. Các phím bấm, di chuyển chuột, thẻ mạng, đĩa, lỗi trang tạo ra các ngắt phần cứng. Các chức năng chờ và tín hiệu, và sleep(), thuộc về thể loại thứ hai đó. Khi một phần cứng gián đoạn làm cho một trình điều khiển được chạy, trình điều khiển thực hiện bất kỳ phần cứng quản lý nó được thiết kế để làm. Nếu trình điều khiển cần báo hiệu hệ điều hành mà một số luồng cần được chạy, (có lẽ một bộ đệm đĩa hiện đã đầy và cần được xử lý), hệ điều hành cung cấp một cơ chế nhập mà trình điều khiển có thể gọi thay vì trực tiếp thực hiện ngắt trả lại chính nó, (quan trọng!).
Ngắt như các ví dụ trên có thể tạo các chuỗi đang chờ sẵn sàng chạy và/hoặc có thể tạo một luồng đang chạy vào trạng thái chờ. Sau khi xử lý mã của ngắt, hệ điều hành áp dụng thuật toán lập lịch trình của nó/s để quyết định xem tập hợp các luồng đang chạy trước ngắt có giống như tập hợp mà bây giờ sẽ được chạy hay không. Nếu họ đang có, hệ điều hành chỉ gián đoạn trả về, nếu không, hệ điều hành phải preempt một hoặc nhiều chủ đề đang chạy. Nếu hệ điều hành cần phải preempt một thread đang chạy trên một lõi CPU mà không phải là một trong đó xử lý ngắt, nó đã giành quyền kiểm soát của lõi CPU đó. Nó thực hiện điều này bằng phương tiện ngắt phần cứng 'thực' - trình điều khiển bộ vi xử lý giữa hệ điều hành thiết lập một tín hiệu phần cứng làm gián đoạn lõi đang chạy luồng mà nó được ưu tiên.
Khi một chuỗi được đặt trước vào mã OS, hệ điều hành có thể lưu một ngữ cảnh hoàn chỉnh cho chuỗi.Một số thanh ghi sẽ được lưu vào ngăn xếp của luồng bằng cách ngắt mục và do đó việc lưu ngăn xếp của chuỗi sẽ 'lưu' tất cả các thanh ghi đó một cách hiệu quả, nhưng hệ điều hành thông thường sẽ cần phải làm nhiều hơn, ví dụ. bộ nhớ đệm có thể cần được xả, trạng thái FPU có thể cần phải được lưu lại và trong trường hợp luồng mới được chạy thuộc một quy trình khác với quy trình được ưu tiên, các thanh ghi bảo vệ quản lý bộ nhớ sẽ cần được hoán đổi . Thông thường, hệ điều hành chuyển từ ngăn xếp luồng bị gián đoạn sang ngăn xếp hệ điều hành riêng càng sớm càng tốt để tránh gây ra các yêu cầu ngăn xếp hệ điều hành trên mỗi ngăn xếp luồng.
Khi ngữ cảnh/s được lưu, hệ điều hành có thể 'hoán đổi trong' ngữ cảnh mở rộng cho s/s mới sẽ được chạy. Bây giờ, hệ điều hành cuối cùng có thể tải stack-pointer cho thread mới/s và thực hiện ngắt-trả về để làm cho các chủ đề sẵn sàng mới của nó đang chạy.
Hệ điều hành sau đó không làm gì cả. Các luồng chạy chạy cho đến khi một ngắt khác, (cứng hoặc mềm), xảy ra.
Những điểm quan trọng:
1) kernel hệ điều hành nên được xem xét như một ngắt-handler lớn mà có thể quyết định làm gián đoạn-trở lại một bộ khác nhau của chủ đề hơn so với những người bị gián đoạn.
2) Hệ điều hành có thể kiểm soát và dừng nếu cần thiết, bất kỳ luồng nào trong bất kỳ quy trình nào, bất kể trạng thái của nó ở trạng thái nào hoặc lõi nào có thể đang chạy.
3) Tính năng lập lịch và gửi đi ưu tiên không tạo ra tất cả sự cố đồng bộ hóa vv được đăng tải trên các diễn đàn này. Nhược điểm lớn là phản ứng nhanh ở cấp độ luồng tới các ngắt cứng. Nếu không có điều này, tất cả những ứng dụng hiệu suất cao mà bạn chạy trên PC của bạn - phát trực tuyến video, mạng nhanh, v.v., hầu như không thể.
4) Bộ hẹn giờ hệ điều hành chỉ là một trong một bộ ngắt lớn có thể thay đổi tập hợp các chuỗi đang chạy. 'Time-slicing', (ugh - tôi ghét thuật ngữ đó), giữa các chủ đề sẵn sàng chỉ xảy ra khi máy tính bị quá tải, tức là. tập hợp các chuỗi sẵn sàng lớn hơn số lõi CPU có sẵn để chạy chúng. Nếu bất kỳ văn bản nào có ý định giải thích việc lập lịch biểu của hệ điều hành đề cập đến 'cắt thời gian' trước khi 'gián đoạn', điều này có thể gây nhầm lẫn nhiều hơn giải thích. Bộ đếm thời gian gián đoạn chỉ là 'đặc biệt' trong nhiều cuộc gọi hệ thống có thời gian chờ để sao lưu chức năng chính của chúng, (OK, cho sleep(), timeout IS là chức năng chính :).
Chỉ cần tự hỏi, đây có phải là cách chức năng chờ đợi hoạt động trong nội bộ không? (Không bao gồm ngoại lệ). – Mehrdad
@ Mehrdad- Thông thường là không. Thông thường các chủ đề được đặt trong một "hàng đợi" và không được cung cấp bất kỳ thời gian xử lý nào. Khi một số sự kiện xảy ra sẽ đánh thức chúng, chúng được đặt trở lại hàng đợi để chúng được lên kế hoạch. Điều này có nghĩa rằng bạn có thể có một triệu chủ đề ngủ mà không bị mất hiệu suất nếu chỉ có hai hoặc ba luồng hoạt động cùng một lúc. – templatetypedef
@templatetypedef: Vậy thì hệ điều hành chính xác tìm hiểu xem các luồng có nên được đánh thức tại một lát thời gian cụ thể không? Không nên kiểm tra trạng thái của luồng trong một vòng lặp ở mọi lát thời gian? – Mehrdad