2012-04-01 22 views
8

Tôi đang làm việc để triển khai một máy chủ cơ sở dữ liệu trong C sẽ xử lý các yêu cầu từ nhiều máy khách. Để làm như vậy tôi đang sử dụng fork() để xử lý các kết nối cho các máy khách cá nhân.Chia sẻ bộ nhớ heap với fork()

Máy chủ lưu trữ dữ liệu trong heap bao gồm một con trỏ gốc vào bảng băm của các bản ghi được cấp động. Các bản ghi là các cấu trúc có các con trỏ đến các kiểu dữ liệu khác nhau. Tôi muốn cho các quá trình để có thể chia sẻ dữ liệu này để khi một khách hàng thực hiện một thay đổi cho đống, những thay đổi sẽ được hiển thị cho các khách hàng khác.

Tôi đã học được rằng fork() sử dụng COW (Copy On Write) và sự hiểu biết của tôi là nó sẽ sao chép bộ nhớ heap (và ngăn xếp) của quá trình cha mẹ khi trẻ sẽ cố gắng sửa đổi dữ liệu trong bộ nhớ.

Tôi đã phát hiện ra rằng tôi có thể sử dụng thư viện shm để chia sẻ bộ nhớ.

-Nó có đủ để chia sẻ con trỏ gốc của cơ sở dữ liệu hay tôi phải làm cho tất cả bộ nhớ được phân bổ như được chia sẻ?

-Nếu một đứa trẻ cấp phát bộ nhớ, phụ huynh/trẻ em khác có thể truy cập vào bộ nhớ đó không?

-Ngoài ra nếu một đứa trẻ cấp phát bộ nhớ và sau đó bị giết sẽ bộ nhớ được phân bổ vẫn ở lại trên heap?

Ví dụ: mã dưới đây là cách hợp lệ để chia sẻ bộ nhớ heap (trong shared_string)? Nếu một đứa trẻ sử dụng mã tương tự (tức là bắt đầu từ // bắt đầu) thì những đứa trẻ khác có thể đọc/ghi nó trong khi đứa trẻ đang chạy và sau khi nó đã chết không?

key_t key; 
int shmid; 

key = ftok("/tmp",'R'); 
shmid = shmget(key, 1024, 0644 | IPC_CREAT); 

//start 
char * string; 
string = malloc(sizeof(char) * 10); 

strcpy(string, "a string"); 

char * shared_string; 

shared_string = shmat(shmid, string, 0); 

strcpy(shared_string, string); 
+2

Việc sử dụng * đề tài * phổ biến hơn nếu bạn muốn chia sẻ bộ nhớ giữa các phần của cùng một chương trình. Nhưng bạn phải rất cẩn thận về cách bạn đồng bộ hóa quyền truy cập vào cấu trúc dữ liệu được chia sẻ với khóa, v.v. – alberge

+1

Vâng, bạn cần sử dụng bộ nhớ dùng chung cho tất cả nội dung bạn muốn chia sẻ. –

+0

Chỉ có thể chia sẻ shm, nếu bạn cấp phát bộ nhớ mới, nó cũng phải được bật, không cắt ngắn. – pizza

Trả lời

3

Trước hết, fork hoàn toàn không phù hợp với những gì bạn đang cố gắng đạt được. Ngay cả khi bạn có thể làm cho nó hoạt động, đó là một hack khủng khiếp. Nói chung, fork chỉ hoạt động cho các chương trình rất đơn giản, và tôi sẽ đi xa như vậy để nói rằng fork không bao giờ được sử dụng trừ khi được theo dõi nhanh chóng bởi exec, nhưng đó là ngoài điểm ở đây. Bạn thực sự nên sử dụng các chủ đề.

Với cách nói đó, cách duy nhất để có bộ nhớ được chia sẻ giữa cha mẹ và con sau fork và nơi cùng một con trỏ hợp lệ trong cả hai, là mmap (hoặc shmat, nhưng đó là rất nhiều tiền) một tệp hoặc bản đồ ẩn danh với MAP_SHARED trước fork. Bạn không thể tạo bộ nhớ dùng chung mới như sau fork vì không đảm bảo rằng nó sẽ được ánh xạ ở cùng một dải địa chỉ trong cả hai.

Chỉ cần không sử dụng fork. Nó không phải là công cụ thích hợp cho công việc.

+0

Đồng ý. Fork() tạo ra một cá thể riêng biệt, chủ yếu giống hệt nhau. Threading là những gì là cần thiết. Hoặc asio, có thể phức tạp, nhưng Boost làm một công việc khá tốt khi cung cấp nó. –

0

Nếu bạn phải là bạn fork, bộ nhớ dùng chung có vẻ là lựa chọn 'duy nhất'.

Thực ra, tôi nghĩ trong cảnh của bạn, chuỗi chỉ phù hợp hơn.

Nếu bạn không muốn là đa luồng.Đây là sự lựa chọn khác, bạn chỉ có thể sử dụng một quá trình & chế độ một chủ đề, như redis

Với chế độ này, bạn không cần phải lo lắng về điều gì đó như lock và nếu bạn muốn mở rộng quy mô, chỉ cần thiết kế một chính sách tuyến đường , vì tuyến đường có giá trị băm của key

1

Nó có đủ để chia sẻ con trỏ gốc của cơ sở dữ liệu hay tôi phải làm tất cả bộ nhớ được phân bổ như được chia sẻ?

Không, bởi vì mỗi quá trình sẽ có phạm vi bộ nhớ riêng. Copy-on-write là một tối ưu hóa không gian hạt nhân minh bạch cho không gian người dùng.

Như những người khác đã nói, các tệp SHM hoặc mmap'd là cách duy nhất để chia sẻ bộ nhớ giữa các quy trình riêng biệt.

2

Xin lỗi vì đã trả lời một tháng sau, nhưng tôi không nghĩ rằng câu trả lời hiện tại đã đưa ra những gì OP yêu cầu.

Tôi nghĩ bạn về cơ bản đang tìm cách làm những gì được thực hiện bởi Redis (và có thể đẩy những người khác). Chúng mô tả nó trong http://redis.io/topics/persistence (tìm kiếm "copy-on-write").

  • đề đánh bại mục đích
  • bộ nhớ chia sẻ cổ điển (shm, bộ nhớ ánh xạ) cũng đánh bại mục đích

Lợi ích đầu tiên để sử dụng phương pháp này là tránh khóa, có thể là một nỗi đau để nhận được ngay.

Theo như tôi hiểu nó ý tưởng sử dụng COW là:

  • nĩa khi bạn muốn viết, không phải trước
  • đứa trẻ (lại) ghi dữ liệu vào đĩa, sau đó ngay lập tức thoát khỏi số
  • cha mẹ tiếp tục thực hiện công việc của mình và phát hiện (SIGCHLD) khi đứa trẻ đã thoát. Nếu trong khi thực hiện công việc, cha mẹ sẽ kết thúc việc thay đổi giá trị băm, hạt nhân sẽ thực hiện một bản sao cho các khối bị ảnh hưởng (thuật ngữ đúng?).
    Một "cờ bẩn" được sử dụng để theo dõi xem cần có một ngã ba mới để thực hiện ghi mới hay không.

Những điều cần xem ra cho:

  • Hãy chắc chắn rằng chỉ có một con nổi bật
  • an toàn giao dịch: viết vào một tập tin tạm thời đầu tiên, sau đó di chuyển nó qua để bạn luôn có một bản sao hoàn chỉnh, có lẽ việc giữ trước xung quanh di chuyển không phải là nguyên tử.
  • kiểm tra nếu bạn sẽ có vấn đề với các nguồn lực khác mà có được nhân đôi (file descriptor, hủy toàn cầu trong C++)

Bạn có thể muốn tận ngây ngô tại redis code cũng

+0

Một tập tin tạm thời không thật sự cần thiết: bạn có thể sử dụng một đường ống để truyền đạt các thay đổi do đứa trẻ khởi xướng lại cho cha mẹ. Với cách tiếp cận đó, mỗi đứa trẻ sẽ có một cái nhìn nhất quán, nguyên tử của toàn bộ dữ liệu trong khi người chủ không cần bất kỳ khóa nào để đảm bảo tính nhất quán. Bằng cách đó, bạn thậm chí có thể có nhiều trẻ em cùng một lúc, mỗi đứa trẻ có cái nhìn không thay đổi, nhất quán của dữ liệu và một người chủ cập nhật dữ liệu theo hướng dẫn của trẻ em giữa những đứa trẻ mới sinh. – cmaster

+0

@cmaster tệp tạm thời KHÔNG được dùng làm khóa, đồng bộ giữa các chủ đề hoặc bất kỳ thứ gì tương tự. Nếu cho nguyên tử trong hệ thống tập tin. Bạn có thể gặp sự cố giữa chừng và có một tệp không hợp lệ. nếu bạn viết xong thì bạn đổi tên (nguyên tử). – nhed

+0

Tôi chưa bao giờ nghĩ như vậy. Những gì tôi đã cố gắng chỉ ra là, forking có thể được xem như là một trạm kiểm soát giá rẻ của tất cả các dữ liệu trong bộ nhớ. Một quá trình có thể tự do phân tích dữ liệu, trong khi tổng thể đã bận rộn áp dụng các thay đổi được truyền lại từ một đứa trẻ khác. Trong một thiết lập như vậy, bạn không cần phải ghi bất kỳ dữ liệu nào vào đĩa để giao tiếp. Và điểm của một thiết lập như vậy sẽ không được lưu giữ dữ liệu, nhưng để đảm bảo khả năng truy cập đồng thời, chống đạn vào cơ sở dữ liệu trong bộ nhớ. – cmaster

1

Nhiều máy chủ HTTP phổ biến sử dụng fork() để tận dụng lợi thế của nhiều bộ xử lý, Nginx là một trong số đó.Threading mang đến cho nó toàn bộ các cơn đau đầu mà cá nhân tôi muốn tránh trừ khi thực sự cần thiết, như chương trình của bạn sẽ không bao giờ bị treo máy do lỗi đa luồng (trải nghiệm của tôi với mã luồng của người khác).

Tính năng đa xử lý cho phép bạn sử dụng tất cả các bộ xử lý trên máy của bạn mà không cần chia sẻ bộ nhớ giữa các chuỗi thực thi, mặc định tránh tất cả các lỗi thông thường, đa luồng, vô tận.

Tôi thích ngủ vào ban đêm mà không nhận được những cuộc gọi 2 giờ sáng, khi biết trang web của tôi phải đối mặt, máy chủ thông lượng cao sẽ không gặp sự cố vì tôi không thấy một trong hàng tá lỗ hổng đa luồng ngày hôm đó.

Có nhiều trường hợp bộ nhớ dùng chung không bị đau, chẳng hạn như, nếu dữ liệu trong bộ nhớ dùng chung chỉ đọc. Bạn không phải lo lắng về việc khóa vv.