2016-02-01 15 views
11

Tôi đang thực hiện một số nghiên cứu về chủ đề màu xanh lá cây C++, chủ yếu là boost::coroutine2 và các chức năng POSIX tương tự như makecontext()/swapcontext() và lập kế hoạch triển khai thư viện chuỗi màu xanh lá cây C++ ở trên cùng của boost::coroutine2. Cả hai yêu cầu mã người dùng để phân bổ một ngăn xếp cho mỗi hàm/coroutine mới.Phân bổ ngăn xếp cho chủ đề màu xanh lá cây C++

Nền tảng mục tiêu của tôi là x64/Linux. Tôi muốn thư viện chủ đề màu xanh của tôi phù hợp để sử dụng chung, vì vậy ngăn xếp sẽ mở rộng theo yêu cầu (giới hạn trên hợp lý là tốt, ví dụ 10MB), sẽ rất tuyệt nếu ngăn xếp có thể co lại khi quá nhiều bộ nhớ không được sử dụng (không bắt buộc). Tôi đã không tìm ra một thuật toán thích hợp để phân bổ ngăn xếp.

Sau khi một số googling, tôi đã tìm ra một vài lựa chọn bản thân mình:

  1. sử dụng chia ngăn xếp được thực hiện bởi trình biên dịch (gcc -fsplit-stack), nhưng chia ngăn xếp có hiệu suất trên cao. Go đã di chuyển ra khỏi ngăn xếp chia nhỏ vì lý do hiệu suất.
  2. phân bổ một bộ nhớ lớn với mmap() hy vọng hạt nhân đủ thông minh để rời khỏi bộ nhớ vật lý chưa được phân bổ và chỉ phân bổ khi ngăn xếp được truy cập. Trong trường hợp này, chúng tôi đang ở lòng thương xót của hạt nhân.
  3. đặt trước dung lượng bộ nhớ lớn với mmap(PROT_NONE) và thiết lập bộ xử lý tín hiệu SIGSEGV. Trong trình xử lý tín hiệu, khi SIGSEGV gây ra bởi truy cập ngăn xếp (bộ nhớ được truy cập nằm bên trong bộ nhớ lớn được dành riêng), cấp phát bộ nhớ cần thiết với mmap(PROT_READ | PROT_WRITE). Đây là vấn đề cho cách tiếp cận này: mmap() không an toàn không đồng bộ, không thể gọi bên trong bộ xử lý tín hiệu. Nó vẫn có thể được thực hiện, rất khó khăn mặc dù: tạo một luồng khác trong khi khởi động chương trình để cấp phát bộ nhớ và sử dụng pipe() + read()/write() để gửi thông tin phân bổ bộ nhớ từ trình xử lý tín hiệu đến luồng.

Một vài câu hỏi thêm về tùy chọn 3:

  1. Tôi không chắc chắn trên không thực hiện của phương pháp này,/như thế nào xấu kernel/CPU thực hiện khi không gian bộ nhớ là rất rời rạc do hàng ngàn cuộc gọi mmap()?
  2. Cách tiếp cận này có đúng không nếu bộ nhớ chưa phân bổ được truy cập trong không gian hạt nhân? ví dụ. khi read() được gọi?

Có bất kỳ lựa chọn nào khác (tốt hơn) cho phân bổ ngăn xếp cho chuỗi màu xanh lục không? Ngăn xếp chuỗi màu xanh lá cây được phân bổ như thế nào trong các triển khai khác, ví dụ: Go/Java?

+1

Mặc dù 'mmap' không an toàn không đồng bộ theo POSIX, nhưng nó thực sự không an toàn trong Linux và hầu như mọi biến thể UNIX hợp lý có thể sử dụng được ở đó. –

+0

@ChrisDodd Tôi có thể hỏi tại sao 'mmap' có thể tốt cho chủ đề màu xanh lá cây không? Tôi không phải là chuyên gia nhưng tôi muốn biết. – VermillionAzure

+0

@ChrisDodd Tôi không tìm thấy bất kỳ trang người đàn ông/liên kết về điều này, bạn có thể nhớ xin vui lòng cho tôi một liên kết? – user416983

Trả lời

0

Lý do mmap? Khi bạn phân bổ với bộ nhớ mới (hoặc malloc), bộ nhớ không bị ảnh hưởng và chắc chắn không được ánh xạ.

const int STACK_SIZE = 10 * 1024*1024; 
char*p = new char[STACK_SIZE*numThreads]; 

p hiện có đủ bộ nhớ cho chủ đề bạn muốn. Khi bạn cần bộ nhớ, bắt đầu truy cập p + STACK_SIZE * i

+2

Điều đó chắc chắn không được đảm bảo để được unmapped, hoặc khởi tạo cho bất kỳ giá trị cụ thể. Sử dụng GNU libc malloc, một phân bổ lớn cuối cùng sẽ gọi hàm mmap(). – Matt

1

Cách mà glibc phân bổ ngăn xếp cho các chương trình C bình thường là để mmap một khu vực với cờ mmap sau được thiết kế chỉ dành riêng cho mục đích này:

MAP_GROWSDOWN 
      Used for stacks. Indicates to the kernel virtual memory system 
      that the mapping should extend downward in memory. 

Để tương thích, có lẽ bạn cũng nên sử dụng MAP_STACK. Sau đó, bạn không phải tự viết trình xử lý SIGSEGV và ngăn xếp tự động phát triển.Các giới hạn có thể được đặt như được mô tả ở đây What does "ulimit -s unlimited" do?

Nếu bạn muốn kích thước ngăn xếp được giới hạn, thường là những gì mọi người làm cho trình xử lý tín hiệu nếu họ muốn gọi số sigaltstack(2).

Nhân Linux luôn bản đồ các trang vật lý quay lại trang ảo, bắt lỗi trang khi trang được truy cập lần đầu tiên (có thể không phải trong nhân thời gian thực nhưng chắc chắn trong tất cả các cấu hình khác). Bạn có thể sử dụng giao diện /proc/<pid>/pagemap (hoặc công cụ này tôi đã viết https://github.com/dwks/pagemap) để xác minh điều này nếu bạn quan tâm.

Các vấn đề liên quan