Tại sao tính nhất quán không hợp thành, nhưng tính nhất quán tuần tự thì không


7

Tôi gặp khó khăn khi so sánh hai mô hình nhất quán bộ nhớ này.

Về cơ bản để thống nhất tuần tự tôi nghĩ về mã thực như thế này:

int x, y;

void ThreadA()
{
   x = 20; //Write
   int a = y; //Read
}

void ThreadB()
{
    y = 20;
    int b = x;
}

Trong một môi trường nhất quán tuần tự, không thể ahoặc bkhông thể 20. Đó là a = 20, b = 20hoặc a = 20 && b = 20.

Nhưng làm thế nào để tính nhất quán phù hợp với ví dụ này, và tại sao nó là thành phần?

Câu trả lời:


10

Xin lỗi vì đã trả lời trễ, nhưng tôi vừa tìm thấy câu hỏi (câu hỏi, thực sự). Tôi cũng đang nghiên cứu đồng thời và tôi sẽ cố gắng chia sẻ một số ý tưởng với bạn.

Đầu tiên, hãy bắt đầu với tính nhất quán tuần tự. Một mô hình có thuộc tính này nếu các hoạt động dường như có hiệu lực theo thứ tự chương trình. Nói cách khác, thứ tự các dòng mã được thực thi là thứ tự được chỉ định trong tệp nguồn. Điều kiện tiên quyết này là đặc thù của luồng: các hoạt động liên quan đến các luồng khác nhau không liên quan đến thứ tự chương trình. Vì vậy, thuộc tính cấp các điều sau: các hoạt động được phát hành bởi cùng một luồng được thực hiện theo cùng một thứ tự được chỉ định bởi mã nguồn luồng. Hoạt động được phát hành bởi các chủ đề khác nhau có thể xảy ra theo thứ tự bất kỳ. Điều kiện tiên quyết này có vẻ rõ ràng, nhưng không phải lúc nào cũng được (tối ưu hóa trình biên dịch có thể thay đổi thứ tự các hoạt động được ban hành, do đó làm cho thứ tự chương trình khác với nguồn).

Ví dụ của bạn là đúng, nhưng hãy để tôi cung cấp cho bạn một số người khác. Hãy xem xét chương trình này P1 (Tôi sẽ gắn thẻ từng dòng để tham khảo dễ dàng):

   int x = 1;

   void ThreadA()
   {
A1:    x = x * 2;
A3:    int a = x;
   }

   void ThreadB()
   {
B2:    x = 20;
   }

Có thực hiện tuần tự trong đó, ở cuối, a = 40 không? Có: B2, A1, A3.

B2 và A1 có thể được thực thi theo bất kỳ thứ tự nào (chúng thuộc các luồng khác nhau). A1 được thực thi trước A3 (thứ tự chương trình = thứ tự mã nguồn).

Bây giờ hãy xem xét chương trình này P2:

   int y = 1;

   void ThreadA()
   {
A2:    y = 40;
   }

   void ThreadB()
   {
B1:    y = y / 2;
B3:    int b = y;
   }

Có thực hiện tuần tự trong đó, ở cuối, b = 20? Có: A2, B1, B3.

Thành phần thì sao? Hãy soạn P1 và P2. Chúng tôi nhận được P1∘P2:

   int x = 1;
   int y = 1;

   void ThreadA()
   {
A1:    x = x * 2;
A2:    y = 40;
A3:    int a = x;
   }

   void ThreadB()
   {
B1:    y = y / 2;
B2:    x = 20;
B3:    int b = y;
   }

Nếu tính nhất quán tuần tự là thành phần, thì nên có một thực thi trong đó, ở cuối, a = 40 và b = 20. Đây có phải là trường hợp không? Không. Hãy đưa ra một bằng chứng chính thức oh tại sao nó không thể là trường hợp. Tôi sẽ viết "o1 → o2" để nói rằng hoạt động o1 phải được thực hiện trước khi hoạt động o2.

Trong P1∘P2, do tính nhất quán tuần tự, các phần sau phải giữ: A1 -> A2 và B1 -> B2 (thứ tự chương trình trên mỗi luồng). Để có được a = 40 còn B2 -> A1 phải giữ. Để có được b = 20 cũng phải có A2 -> B1. Bạn có thể thấy chuỗi ưu tiên? A1 -> A2 -> B1 -> B2 -> A1 -> ...

P1 và P2 là nhất quán liên tục, nhưng thành phần của chúng là P1∘P2 thì không. Tính nhất quán tuần tự không phải là thành phần. Ví dụ bạn cung cấp không đủ khó để thể hiện sự thật này.

Bây giờ, hãy xem xét tính nhất quán tĩnh. Thật khó cho tôi để giải thích tính chất này mà không sử dụng mô hình hướng đối tượng. Trong thực tế, tính nhất quán tĩnh có thể được hiểu một cách dễ dàng theo các lời gọi phương thức đang chờ xử lý trên các đối tượng. Tuy nhiên, tôi sẽ cố gắng tuân theo mô hình bắt buộc (các lệnh gọi phương thức đang chờ xử lý trở thành các hàm bắt đầu nhưng chưa hoàn thành, các đối tượng trở thành các biến liên quan đến các hàm).

Một cuộc gọi chức năng được sáng tác bởi một lời gọi và một phản hồi. Một hàm đang chờ xử lý nếu nó được gọi bởi một luồng nhưng nó chưa trả về phản hồi nào cho luồng đó. Khoảng thời gian không hoạt động cho một biến là một khoảng thời gian trong đó không có lệnh gọi hàm đang chờ xử lý (bởi bất kỳ luồng nào) hoạt động trên biến đó. Một mô hình có thuộc tính nhất quán tĩnh nếu các lệnh gọi hoạt động trên cùng một biến và được phân tách bằng một khoảng thời gian hoạt động dường như có hiệu lực theo thứ tự thời gian thực của chúng (một lệnh được chỉ định bởi mã nguồn). Từ quan điểm ngược lại, định nghĩa nói rằng các hoạt động trên cùng một biến được thực hiện bởi các hàm được gọi đồng thời bởi các luồng khác nhau (không được phân tách bằng cách ly) có thể xảy ra theo bất kỳ thứ tự nào.

Tôi đã cố gắng trong nhiều giờ để thiết kế một ví dụ có ý nghĩa chỉ sử dụng các thao tác đọc-ghi để cho bạn thấy sự khác biệt giữa tính nhất quán tĩnh và liên tục, nhưng tôi đã không thành công. Hãy để tôi sử dụng một ví dụ khác liên quan đến bộ. Tôi sẽ sử dụng một vectơ bit để theo dõi các số nguyên nào (từ 0 đến 4) trong tập hợp:

   int set[5] = {0, 0, 0, 0, 0};  // 0 if i-th item is absent, 1 otherwise

   void add(int number) {
L1:    set[number] = 1;
L2:    temp foo = set[0];
   }

   void remove(int number) {
       set[number] = 0;
   }

   int contains(int number) {
       return set[number] == 1;
   }

   void ThreadA()
   {
A1:    add(1);
   }

   void ThreadB()
   {
B1:    add(2);
B2:    remove(2);
B3:    int res = contains(2);
   }

Có thực hiện tuần tự trong đó, ở cuối, res = 1 không? Không: do tính nhất quán tuần tự B1 -> B2 và B2 -> B3, vì vậy B1 -> B3. Vì vậy, remove (2) luôn được thực hiện sau add (2) và chứa (2) sẽ luôn trả về 0.

Có một thực thi tĩnh trong đó, ở cuối, res = 1 không? Đúng! Hãy xem xét việc thực hiện này:

Chủ đề A gọi thêm (1) tại A1.

Chủ đề A thực thi L1 (nhưng không phải L2). // vì có một cuộc gọi đang chờ xử lý trên tập hợp, nên bây giờ Thread B có thể thực hiện B2 trước B1 vì các cuộc gọi này cũng liên quan đến tập hợp

Chủ đề B gọi B2. // gọi + phản hồi

Chủ đề B gọi B1. // gọi + phản hồi

Chủ đề A thực thi L2 và thêm (1) trả lời. // bây giờ có sự im lặng trên tập hợp

Chủ đề B thực thi B3. // gọi + phản hồi

Bây giờ res = 1.

Thật không may, tôi vẫn không thể trả lời câu hỏi mới nhất về lý do tại sao tính nhất quán tĩnh lại là thành phần: Tôi đã tìm thấy câu hỏi của bạn trong khi tôi đang tìm kiếm câu trả lời chính xác này thực sự. Nếu tôi nghĩ ra thứ gì đó tôi sẽ cho bạn biết.

Để đọc tốt về chủ đề này, hãy xem chương 3.3 của cuốn sách "Nghệ thuật lập trình đa bộ xử lý" của Herlihy và Shavit.

EDIT: Tôi vừa tìm thấy một trang tuyệt vời giải thích lý do tại sao tính nhất quán không hoạt động là thành phần. Và đây là một cách đọc rất tốt!

EDIT2: Đã sửa lỗi nhỏ trong ví dụ về tính tổng hợp nhất quán liên tiếp.


Câu trả lời tuyệt vời cho một câu hỏi cổ vũ khó khăn! (Tôi đoán nó đã chạm vào không ai trả lời trong nhiều tháng: P).
William

Tôi có thể hiểu rõ về tính nhất quán tĩnh và tính nhất quán tuần tự riêng lẻ (cũng như tính nhất quán nghiêm ngặt) nhưng tôi cảm thấy vô cùng khó khăn khi liên hệ chúng với nhau. Mặc dù trong ví dụ đầu tiên của bạn nếu thực thi là B2, A1, A3.in trong thời gian thực thì mọi thứ khác ngoài a = 40 sẽ không thể thực hiện được dưới sự nhất quán nghiêm ngặt.
William

Nhưng tôi chỉ không nghĩ rằng tôi hiểu ý nghĩa thực sự của sự nhất quán là "thành phần". Tôi đã đọc ví dụ thứ 3 của bạn như 30 lần (và tất nhiên là mô tả) nhưng chỉ cố gắng để hiểu!
William

Đầu tiên, tôi đã sửa một lỗi nhỏ trong phần mô tả ví dụ P1∘P2. Nhưng tôi nghĩ rằng bạn đã rõ ràng tại sao tính nhất quán tuần tự (SC) không phải là thành phần. Thứ hai, a = 40 không phải là kết quả khả dĩ duy nhất trong ví dụ đầu tiên được cung cấp [giả sử mô hình SC], bởi vì A1, A3, B2 là hợp pháp và dẫn đến a = 20. Mục tiêu ví dụ cuối cùng của tôi là làm nổi bật sự khác biệt giữa SC và tính nhất quán tĩnh (QC) (res = 1 là có thể trong một mô hình và không thể trong mô hình kia). Tôi không đề cập đến chủ đề về khả năng kết hợp QC: vui lòng đọc liên kết được cung cấp trong lần chỉnh sửa đầu tiên để hiểu rõ hơn về chủ đề này
Bản mẫu bóng tối

@William, tôi không hiểu lý do tại sao bạn buộc đối tượng không có khoảng thời gian không hoạt động giữa add (2) và remove (2) (bằng cách giả sử rằng luồng A có lệnh gọi phương thức đang chờ xử lý trên đối tượng). Ngoài ra, sẽ là một vấn đề nếu tôi cho phép Chủ đề A hoàn thành việc thực hiện phương thức add () và sau đó Chủ đề B thực hiện B2, rồi B1. Trình tự này sẽ được nhất quán tĩnh?
Saurabh Raje
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.