Các chủ đề được triển khai như các quy trình trên Linux?


65

Tôi đang xem cuốn sách này , Lập trình Linux nâng cao của Mark Mitchell, Jeffrey Oldham và Alex Samuel. Đó là từ năm 2001, vì vậy một chút cũ. Nhưng dù sao tôi cũng thấy nó khá tốt.

Tuy nhiên, tôi đã đến một điểm khi nó khác với những gì Linux của tôi tạo ra trong đầu ra shell. Trên trang 92 (116 trong trình xem), chương 4.5 Thực hiện chủ đề GNU / Linux bắt đầu bằng đoạn có chứa tuyên bố này:

Việc triển khai các luồng POSIX trên GNU / Linux khác với triển khai luồng trên nhiều hệ thống giống UNIX khác theo một cách quan trọng: trên GNU / Linux, các luồng được thực hiện như các quy trình.

Điều này có vẻ như là một điểm quan trọng và sau đó được minh họa bằng mã C. Đầu ra trong cuốn sách là:

main thread pid is 14608
child thread pid is 14610

Và trong Ubuntu 16.04 của tôi, nó là:

main thread pid is 3615
child thread pid is 3615

ps đầu ra hỗ trợ này.

Tôi đoán một cái gì đó đã thay đổi giữa năm 2001 và bây giờ.

Chương trình con tiếp theo trên trang tiếp theo, Xử lý tín hiệu 4.5.1, được xây dựng dựa trên câu lệnh trước:

Hành vi của sự tương tác giữa các tín hiệu và luồng thay đổi từ một hệ thống giống như UNIX sang hệ thống khác. Trong GNU / Linux, hành vi được quyết định bởi thực tế là các luồng được triển khai như các tiến trình.

Và có vẻ như điều này sẽ còn quan trọng hơn sau này trong cuốn sách. Ai đó có thể giải thích những gì đang xảy ra ở đây?

Tôi đã thấy cái này Có phải các luồng nhân Linux thực sự là các tiến trình kernel? , nhưng nó không giúp được gì nhiều. Tôi bối rối.

Đây là mã 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;
}

1
Tôi không hiểu nguồn gốc của sự nhầm lẫn của bạn là gì. Chủ đề được thực hiện như các quá trình chia sẻ không gian địa chỉ với cha mẹ của chúng.
Johan Myréen

2
@ JohanMyréen Vậy tại sao các chủ đề lại bằng nhau?
Tomasz

À, giờ tôi hiểu rồi. Vâng, một cái gì đó thực sự đã thay đổi. Xem câu trả lời của @ ilkkachu.
Johan Myréen

5
Các luồng vẫn được triển khai dưới dạng các quy trình - tuy nhiên hiện getpidtrả về cái được gọi là ID nhóm luồng và để có một ID duy nhất cho một quy trình bạn cần sử dụng gettid. Tuy nhiên, ngoài kernel, hầu hết mọi người và công cụ sẽ gọi một nhóm luồng là một tiến trình và gọi một tiến trình là một luồng, để thống nhất với các hệ thống khác.
dùng253751

Không hẳn vậy. Một quá trình có bộ nhớ và tập tin riêng mô tả của nó, nó không bao giờ được gọi là một chủ đề, làm như vậy sẽ được phù hợp với các hệ thống khác.
rebierpost

Câu trả lời:


50

Tôi nghĩ rằng phần này của clone(2)trang người đàn ông có thể làm rõ lại sự khác biệt. bộ lọc:

CLONE_THREAD (kể từ Linux 2.4.0-test8)
Nếu CLONE_THREAD được đặt, đứa trẻ được đặt trong cùng một nhóm luồng với quy trình gọi.
Các nhóm luồng là một tính năng được thêm vào trong Linux 2.4 để hỗ trợ khái niệm luồng POSIX của một tập hợp các luồng chia sẻ một PID. Trong nội bộ, PID được chia sẻ này là cái gọi là định danh nhóm luồng (TGID) cho nhóm luồng. Kể từ Linux 2.4, các lệnh gọi tới getpid (2) trả về TGID của người gọi.

Cụm từ "các luồng được triển khai như các tiến trình" đề cập đến vấn đề của các luồng đã có các PID riêng biệt trong quá khứ. Về cơ bản, Linux ban đầu không có các luồng trong một quy trình, chỉ là các quy trình riêng biệt (với các bộ vi xử lý riêng biệt) có thể có một số tài nguyên được chia sẻ, như bộ nhớ ảo hoặc bộ mô tả tệp. CLONE_THREADvà tách ID tiến trình (*) và ID luồng làm cho hành vi của Linux trông giống các hệ thống khác và giống với các yêu cầu POSIX hơn theo nghĩa này. Mặc dù về mặt kỹ thuật, HĐH vẫn không có các triển khai riêng cho các luồng và tiến trình.

Xử lý tín hiệu là một lĩnh vực có vấn đề khác với cách triển khai cũ, điều này được mô tả chi tiết hơn trong bài báo @FooF đề cập đến trong câu trả lời của họ .

Như đã lưu ý trong các bình luận, Linux 2.4 cũng được phát hành vào năm 2001, cùng năm với cuốn sách, vì vậy không có gì đáng ngạc nhiên khi tin tức không được đưa vào bản in đó.


2
các quy trình riêng biệt có thể đã xảy ra để có một số tài nguyên được chia sẻ, như bộ nhớ ảo hoặc mô tả tệp. Đó vẫn là cách các chủ đề Linux hoạt động, với các vấn đề bạn đề cập đã được dọn sạch. Tôi muốn gọi các đơn vị lập lịch được sử dụng trong kernel "thread" hoặc "process" thực sự không liên quan. Thực tế họ bắt đầu trên Linux chỉ được gọi là "quy trình" không có nghĩa đó là tất cả những gì họ đang có.
Andrew Henle

@AndrewHenle, yeah, đã chỉnh sửa một chút. Tôi hy vọng rằng nắm bắt được suy nghĩ của bạn, mặc dù tôi có vẻ khó khăn với từ ngữ. (đi trước và chỉnh sửa phần đó nếu bạn muốn.) Tôi đã hiểu rằng một số HĐH giống Unix khác có sự phân tách luồng khác biệt hơn so với các tiến trình, với Linux là một ngoại lệ chỉ thực sự có một loại phục vụ cả hai chức năng. Nhưng tôi không biết đủ về các hệ thống khác và không có nguồn nào hữu ích, vì vậy thật khó để nói bất cứ điều gì cụ thể.
ilkkachu

@tomas Lưu ý rằng câu trả lời này giải thích cách Linux hoạt động bây giờ. Như gợi ý của ilkkachu, nó hoạt động khác đi khi cuốn sách được viết. Câu trả lời của FooF giải thích cách Linux hoạt động vào thời điểm đó.
Gilles 'SO- ngừng trở nên xấu xa'

38

Bạn đã đúng, thực sự "có gì đó đã thay đổi giữa năm 2001 và bây giờ". Cuốn sách bạn đang đọc mô tả thế giới theo triển khai lịch sử đầu tiên của các chủ đề POSIX trên Linux, được gọi là LinuxThreads (xem thêm Wikipedia bài viết cho một số).

LinuxThreads có một số vấn đề tương thích với tiêu chuẩn POSIX - ví dụ như các luồng không chia sẻ PID - và một số vấn đề nghiêm trọng khác. Để khắc phục những sai sót này, một triển khai khác có tên NPTL (Thư viện chủ đề POSIX gốc) đã được Red Hat dẫn đầu để thêm hỗ trợ thư viện không gian nhân và nhân cần thiết để đạt được sự tuân thủ POSIX tốt hơn (lấy các phần tốt từ một dự án tái hiện cạnh tranh khác của IBM có tên NGPT (" Chủ đề Posix thế hệ tiếp theo "), xem bài viết Wikipedia về NPTL ). Các cờ bổ sung được thêm vào clone(2)lệnh gọi hệ thống (đáng chú ý CLONE_THREAD@ikkkachuchỉ ra trong câu trả lời của anh ấy ) có lẽ là phần rõ ràng nhất trong các sửa đổi kernel. Phần không gian người dùng của tác phẩm cuối cùng đã được tích hợp vào Thư viện GNU C.

Ngày nay, một số SDK Linux nhúng sử dụng triển khai LinuxThreads cũ vì chúng đang sử dụng phiên bản dấu chân bộ nhớ nhỏ hơn của LibC được gọi là uClibc (còn gọi là NetherClibc) và phải mất một số năm đáng kể trước khi triển khai không gian người dùng NPTL từ GNU LibC được chuyển giả định là triển khai phân luồng POSIX mặc định, như nói chung các nền tảng đặc biệt này không cố gắng tuân theo thời trang mới nhất với tốc độ cực nhanh. Điều này có thể được quan sát bằng cách nhận thấy rằng thực sự các PID cho các luồng khác nhau trên các nền tảng đó cũng khác nhau không giống như tiêu chuẩn POSIX chỉ định - giống như cuốn sách bạn đang đọc mô tả. Thật ra một khi bạn gọipthread_create(), bạn đột nhiên tăng số lượng quá trình từ một lên ba vì quá trình bổ sung là cần thiết để giữ cho mớ hỗn độn cùng nhau.

Trang hướng dẫn pthreads (7) của Linux cung cấp một cái nhìn tổng quan toàn diện và thú vị về sự khác biệt giữa hai loại này. Một mô tả khác, mặc dù đã lỗi thời, mô tả về sự khác biệt là bài viết này của Ulrich Depper và Ingo Molnar về thiết kế của NPTL.

Tôi khuyên bạn không nên quá coi trọng phần đó của cuốn sách. Thay vào đó, tôi đề xuất các chủ đề POSIX lập trình của Butenhof và các trang hướng dẫn POSIX và Linux về chủ đề này. Nhiều hướng dẫn về chủ đề này không chính xác.


22

(Không gian người dùng) các luồng không được triển khai như các quy trình như trên Linux, ở chỗ chúng không có không gian địa chỉ riêng, chúng vẫn chia sẻ không gian địa chỉ của quy trình cha.

Tuy nhiên, các luồng này được triển khai để sử dụng hệ thống kế toán quy trình nhân, do đó, được phân bổ ID luồng (TID) của riêng chúng, nhưng được cung cấp cùng một mã PID và 'ID nhóm luồng' (TGID) như quy trình cha - điều này trái ngược với quy trình cha một ngã ba, trong đó một TGID và PID mới được tạo và TID giống như PID.

Vì vậy, có vẻ như các hạt nhân gần đây có một TID riêng có thể được truy vấn, nó khác với các luồng, một đoạn mã phù hợp để hiển thị điều này trong mỗi luồng chính () thread_feft () ở trên là:

    long tid = syscall(SYS_gettid);
    printf("%ld\n", tid);

Vì vậy, toàn bộ mã với điều này sẽ là:

#include <pthread.h>                                                                                                                                          
#include <stdio.h>                                                                                                                                            
#include <unistd.h>                                                                                                                                           
#include <syscall.h>                                                                                                                                          

void* thread_function (void* arg)                                                                                                                             
{                                                                                                                                                             
    long tid = syscall(SYS_gettid);                                                                                                                           
    printf("child thread TID is %ld\n", tid);                                                                                                                 
    fprintf (stderr, "child thread pid is %d\n", (int) getpid ());                                                                                            
    /* Spin forever. */                                                                                                                                       
    while (1);                                                                                                                                                
    return NULL;                                                                                                                                              
}                                                                                                                                                             

int main ()                                                                                                                                                   
{                                                                                                                                               
    pthread_t thread;                                                                               
    long tid = syscall(SYS_gettid);     
    printf("main TID is %ld\n", tid);                                                                                             
    fprintf (stderr, "main thread pid is %d\n", (int) getpid ());                                                    
    pthread_create (&thread, NULL, &thread_function, NULL);                                           
    /* Spin forever. */                                                                                                                                       
    while (1);                                                                                                                                                
    return 0;                                                                                                                                                 
} 

Đưa ra một ví dụ đầu ra của:

main TID is 17963
main thread pid is 17963
thread TID is 17964
child thread pid is 17963

3
@tomas einonm là đúng. Bỏ qua những gì cuốn sách nói, nó rất khó hiểu. Dunno biết tác giả ý tưởng muốn truyền đạt điều gì, nhưng anh thất bại nặng nề. Vì vậy, trong Linux, bạn có các luồng Kernel và các luồng không gian người dùng. Chủ đề hạt nhân về cơ bản là các quá trình không có không gian người dùng. Chủ đề không gian người dùng là chủ đề POSIX bình thường. Các quy trình không gian người dùng chia sẻ các mô tả tệp, có thể chia sẻ các đoạn mã, nhưng sống trong các không gian địa chỉ ảo hoàn toàn riêng biệt. Các luồng không gian người dùng trong một phân đoạn mã chia sẻ quy trình, bộ nhớ tĩnh và heap (bộ nhớ động), nhưng có các thanh ghi bộ xử lý riêng biệt và các ngăn xếp.
Boris Burkov

8

Về cơ bản, thông tin trong cuốn sách của bạn là chính xác về mặt lịch sử, vì lịch sử triển khai các luồng trên Linux rất đáng xấu hổ. Câu trả lời này của tôi cho một câu hỏi liên quan về SO cũng đóng vai trò là câu trả lời cho câu hỏi của bạn:

https://stackoverflow.com/questions/9154671/distcellence-b between-Processes-and-threads-in-linux / 9154725 # 9154725

Những sự nhầm lẫn này đều xuất phát từ thực tế là các nhà phát triển kernel ban đầu có quan điểm không hợp lý và sai lầm rằng các luồng có thể được thực hiện gần như hoàn toàn trong không gian người dùng bằng cách sử dụng các quy trình kernel như nguyên thủy, miễn là kernel cung cấp cách để họ chia sẻ bộ nhớ và mô tả tệp . Điều này dẫn đến việc triển khai các chủ đề POSIX của LinuxThreads rất tệ, đây là một cách hiểu sai vì nó không đưa ra bất cứ điều gì giống như ngữ nghĩa của chủ đề POSIX. Cuối cùng, LinuxThreads đã được thay thế (bởi NPTL), nhưng vẫn còn rất nhiều thuật ngữ khó hiểu và hiểu lầm.

Điều đầu tiên và quan trọng nhất cần nhận ra là "PID" có nghĩa là những thứ khác nhau trong không gian kernel và không gian người dùng. Cái mà kernel gọi là PID thực sự là id id cấp độ kernel (thường được gọi là TID), không bị nhầm lẫn với pthread_tđó là một định danh riêng. Mỗi luồng trên hệ thống, cho dù trong cùng một quy trình hoặc một quy trình khác nhau, đều có một TID duy nhất (hoặc "PID" trong thuật ngữ của kernel).

Mặt khác, cái được coi là một PID theo nghĩa "quy trình" POSIX, được gọi là "ID nhóm luồng" hoặc "TGID" trong kernel. Mỗi tiến trình bao gồm một hoặc nhiều luồng (các tiến trình kernel), mỗi luồng có TID (kernel kernel) của riêng chúng, nhưng tất cả đều chia sẻ cùng một TGID, bằng với TID (PID nhân) của luồng ban đầu mainchạy.

Khi tophiển thị cho bạn các chủ đề, nó hiển thị TID (PID nhân), không hiển thị PID (nhân TGID) và đây là lý do tại sao mỗi luồng có một luồng riêng biệt.

Với sự ra đời của NPTL, hầu hết các cuộc gọi hệ thống có đối số PID hoặc hành động theo quy trình gọi đã được thay đổi để coi PID là một TGID và hoạt động trên toàn bộ "nhóm luồng" (quy trình POSIX).


8

Trong nội bộ, không có những thứ như các tiến trình hoặc luồng trong kernel linux. Các tiến trình và luồng là một khái niệm chủ yếu là người dùng, hạt nhân chỉ nhìn thấy "các tác vụ", là một đối tượng có thể lập lịch biểu có thể chia sẻ không, một số hoặc tất cả tài nguyên của nó với các tác vụ khác. Chủ đề là các tác vụ đã được cấu hình để chia sẻ hầu hết các tài nguyên của nó (không gian địa chỉ, mmaps, ống dẫn, xử lý tệp mở, ổ cắm, v.v.) với tác vụ chính và các quy trình là các tác vụ đã được định cấu hình để chia sẻ tài nguyên tối thiểu với tác vụ chính .

Khi bạn sử dụng API Linux trực tiếp ( clone () , thay vì fork ()pthread_create () ), thì bạn sẽ linh hoạt hơn nhiều trong việc xác định bao nhiêu tài nguyên để chia sẻ hoặc không chia sẻ và bạn có thể tạo các tác vụ không hoàn toàn quá trình cũng không hoàn toàn một chủ đề. Nếu bạn sử dụng trực tiếp các cuộc gọi cấp thấp này, bạn cũng có thể tạo một tác vụ với một TGID mới (do đó được coi là một quá trình của hầu hết các công cụ người dùng) thực sự chia sẻ tất cả tài nguyên của nó với tác vụ chính hoặc ngược lại, để tạo một tác vụ với TGID được chia sẻ (do đó được xử lý như một luồng bởi hầu hết các công cụ người dùng) không chia sẻ tài nguyên với tác vụ chính của nó.

Trong khi Linux 2.4 thực hiện TGID, điều này chủ yếu chỉ vì lợi ích của kế toán tài nguyên. Nhiều người dùng và công cụ không gian người dùng thấy hữu ích khi có thể nhóm các nhiệm vụ liên quan lại với nhau và báo cáo việc sử dụng tài nguyên của họ với nhau.

Việc thực hiện các tác vụ trong Linux trôi chảy hơn nhiều so với các quy trình và thế giới quan được trình bày bởi các công cụ không gian người dùng.


Bài báo @FooF được liên kết để mô tả một số điểm trong đó hạt nhân phải coi các tiến trình và luồng là các thực thể riêng biệt (ví dụ: xử lý tín hiệu và exec ()), vì vậy sau khi đọc nó, tôi thực sự sẽ không nói rằng "không có như vậy điều như các quá trình hoặc chủ đề trong nhân linux. "
ilkkachu

5

Linus Torvalds đã tuyên bố trong một bài đăng danh sách gửi thư kernel vào năm 1996 rằng, cả hai luồng và quy trình được coi là một 'bối cảnh thực thi' ", đó là" chỉ là một tập hợp của tất cả các trạng thái của CoE .... bao gồm những thứ như CPU trạng thái, trạng thái MMU, quyền và các trạng thái giao tiếp khác nhau (tệp mở, trình xử lý tín hiệu, v.v.) ".

// simple program to create threads that simply sleep
// compile in debian jessie with apt-get install build-essential
// and then g++ -O4 -Wall -std=c++0x -pthread threads2.cpp -o threads2
#include <string>
#include <iostream>
#include <thread>
#include <chrono>

// how many seconds will the threads sleep for?
#define SLEEPTIME 100
// how many threads should I start?
#define NUM_THREADS 25

using namespace std;

// The function we want to execute on the new thread.
void threadSleeper(int threadid){
    // output what number thread we've created
    cout << "task: " << threadid << "\n";
    // take a nap and sleep for a while
    std::this_thread::sleep_for(std::chrono::seconds(SLEEPTIME));
}

void main(){
    // create an array of thread handles
    thread threadArr[NUM_THREADS];
    for(int i=0;i<NUM_THREADS;i++){
        // spawn the threads
        threadArr[i]=thread(threadSleeper, i);
    }
    for(int i=0;i<NUM_THREADS;i++){
        // wait for the threads to finish
        threadArr[i].join();
    }
    // program done
    cout << "Done\n";
    return;
}

Như bạn có thể thấy chương trình này sẽ sinh ra 25 luồng cùng một lúc, mỗi luồng sẽ ngủ trong 100 giây và sau đó tham gia lại chương trình chính. Sau khi tất cả 25 luồng đã tham gia lại chương trình, chương trình đã hoàn tất và sẽ thoát.

Sử dụng topbạn sẽ có thể thấy 25 phiên bản của chương trình "chủ đề 2". Nhưng bé chán quá. Đầu ra ps auwxthậm chí còn ít thú vị hơn ... NHƯNG ps -eLftrở nên thú vị.

UID        PID  PPID   LWP  C NLWP STIME TTY          TIME CMD
debian     689   687   689  0    1 14:52 ?        00:00:00 sshd: debian@pts/0  
debian     690   689   690  0    1 14:52 pts/0    00:00:00 -bash
debian    6217   690  6217  0    1 15:04 pts/0    00:00:00 screen
debian    6218  6217  6218  0    1 15:04 ?        00:00:00 SCREEN
debian    6219  6218  6219  0    1 15:04 pts/1    00:00:00 /bin/bash
debian    6226  6218  6226  0    1 15:04 pts/2    00:00:00 /bin/bash
debian    6232  6219  6232  0   26 15:04 pts/1    00:00:00 ./threads2
debian    6232  6219  6233  0   26 15:04 pts/1    00:00:00 ./threads2
debian    6232  6219  6234  0   26 15:04 pts/1    00:00:00 ./threads2
debian    6232  6219  6235  0   26 15:04 pts/1    00:00:00 ./threads2
debian    6232  6219  6236  0   26 15:04 pts/1    00:00:00 ./threads2
debian    6232  6219  6237  0   26 15:04 pts/1    00:00:00 ./threads2
debian    6232  6219  6238  0   26 15:04 pts/1    00:00:00 ./threads2
debian    6232  6219  6239  0   26 15:04 pts/1    00:00:00 ./threads2
debian    6232  6219  6240  0   26 15:04 pts/1    00:00:00 ./threads2
debian    6232  6219  6241  0   26 15:04 pts/1    00:00:00 ./threads2
debian    6232  6219  6242  0   26 15:04 pts/1    00:00:00 ./threads2
debian    6232  6219  6243  0   26 15:04 pts/1    00:00:00 ./threads2
debian    6232  6219  6244  0   26 15:04 pts/1    00:00:00 ./threads2
debian    6232  6219  6245  0   26 15:04 pts/1    00:00:00 ./threads2
debian    6232  6219  6246  0   26 15:04 pts/1    00:00:00 ./threads2
debian    6232  6219  6247  0   26 15:04 pts/1    00:00:00 ./threads2
debian    6232  6219  6248  0   26 15:04 pts/1    00:00:00 ./threads2
debian    6232  6219  6249  0   26 15:04 pts/1    00:00:00 ./threads2
debian    6232  6219  6250  0   26 15:04 pts/1    00:00:00 ./threads2
debian    6232  6219  6251  0   26 15:04 pts/1    00:00:00 ./threads2
debian    6232  6219  6252  0   26 15:04 pts/1    00:00:00 ./threads2
debian    6232  6219  6253  0   26 15:04 pts/1    00:00:00 ./threads2
debian    6232  6219  6254  0   26 15:04 pts/1    00:00:00 ./threads2
debian    6232  6219  6255  0   26 15:04 pts/1    00:00:00 ./threads2
debian    6232  6219  6256  0   26 15:04 pts/1    00:00:00 ./threads2
debian    6232  6219  6257  0   26 15:04 pts/1    00:00:00 ./threads2
debian    6260  6226  6260  0    1 15:04 pts/2    00:00:00 ps -eLf

Bạn có thể thấy ở đây tất cả 26 CoE mà thread2chương trình đã tạo. Tất cả đều có chung ID quy trình (PID) và ID quy trình gốc (PPID) nhưng mỗi người có một ID LWP khác nhau (quy trình trọng lượng nhẹ) và số lượng LWP (NLWP) cho biết có 26 CoE - chương trình chính và 25 chủ đề sinh ra bởi nó.


Đúng, một chủ đề chỉ là một quá trình nhẹ (LWP)
fpmurphy

2

Khi nói đến các quy trình và chủ đề của Linux là loại tương tự. Điều đó có nghĩa là chúng được tạo với cùng một lệnh gọi hệ thống : clone.

Nếu bạn nghĩ về nó, sự khác biệt giữa các luồng và các tiến trình là trong đó các đối tượng kernel sẽ được chia sẻ bởi con và cha mẹ. Đối với các quy trình, nó không nhiều: mô tả tệp mở, các phân đoạn bộ nhớ chưa được ghi vào, có thể là một số khác mà tôi không thể nghĩ ra khỏi đỉnh đầu. Đối với các chủ đề, rất nhiều đối tượng được chia sẻ, nhưng không phải tất cả.

Điều làm cho các luồng và các đối tượng gần hơn trong Linux là unsharecuộc gọi hệ thống. Các đối tượng hạt nhân bắt đầu được chia sẻ có thể không được chia sẻ sau khi tạo luồng. Vì vậy, bạn có thể có hai luồng của cùng một quy trình có không gian mô tả tệp khác nhau (bằng cách hủy bỏ việc chia sẻ mô tả tệp sau khi các luồng được tạo). Bạn có thể tự kiểm tra nó bằng cách tạo một luồng, gọi unsharecả hai luồng và sau đó đóng tất cả các tệp và mở tệp mới, đường ống hoặc đối tượng trong cả hai luồng. Sau đó nhìn vào /proc/your_proc_fd/task/*/fdvà bạn sẽ thấy rằng mỗi task(mà bạn đã tạo như một chuỗi) sẽ có các fd khác nhau.

Trong thực tế, cả việc tạo ra các luồng mới và các tiến trình mới đều là các thường trình thư viện gọi clonebên dưới và chỉ định đối tượng hạt nhân nào mà process-thread-thingamajig (tức là task) mới tạo sẽ chia sẻ với tiến trình / luồng gọi.

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.