2009-03-24 42 views
7

Nếu tôi có một biến địa phương như vậy:an toàn Chủ đề và các biến địa phương

Increment() 
{ 
    int i = getFromDb(); // get count for a customer from db 
}; 

Và đây là một lớp dụ mà được tăng lên (mỗi lần một khách hàng - một đối tượng dụ - làm cho một sự mua hàng), là thế này chủ đề biến an toàn? Tôi nghe nói rằng các biến cục bộ là luồng an toàn vì mỗi luồng đều có ngăn xếp riêng, v.v.

Ngoài ra, tôi có nghĩ rằng biến này là trạng thái chia sẻ không? Những gì tôi thiếu trong suy nghĩ là biến này sẽ làm việc với các đối tượng khách hàng khác nhau (ví dụ: John, Paul, v.v.) vì vậy là luồng an toàn nhưng đây là suy nghĩ thiếu sót và một chút thiếu kinh nghiệm trong lập trình đồng thời. Điều này nghe có vẻ rất ngây thơ, nhưng sau đó tôi không có nhiều kinh nghiệm trong việc viết mã đồng thời như tôi nói chung, mã hóa đồng bộ.

EDIT: Ngoài ra, hàm getFromDb() không phải là một phần của câu hỏi và tôi không mong đợi bất cứ ai đoán về an toàn luồng của nó vì nó chỉ là một cuộc gọi để chỉ ra giá trị được gán từ một hàm dữ liệu từ db. :)

CHỈNH SỬA 2: Đồng thời, đảm bảo an toàn chủ đề của getFromDb vì nó chỉ thực hiện thao tác đọc.

Trả lời

33

i được khai báo là một (phương pháp) biến địa phương, vì vậy nó chỉ thường tồn tại trong ngăn xếp khung của Increment() - vì vậy có, i là chủ đề an toàn ... (mặc dù tôi không thể bình luận trên getFromDb).

trừ nếu:

  • Increment là một khối iterator (tức là sử dụng yield return hoặc yield break)
  • i được sử dụng trong một phương pháp vô danh (delegate { i = i + 1;}) hoặc lambda (foo => {i=i+foo;}

Trong hai trường hợp trên, có một số trường hợp khi nó có thể được tiếp xúc bên ngoài ngăn xếp. ou đang làm một trong hai.

Lưu ý rằng lĩnh vực (biến trên lớp) là không thread-an toàn, khi chúng được trivially tiếp xúc với các chủ đề khác. Điều này thậm chí còn đáng chú ý hơn với các trường static vì tất cả các chuỗi sẽ tự động chia sẻ cùng một trường (ngoại trừ trường tĩnh-tĩnh).

+0

+1 cho đầy đủ (thảo luận về các phương thức anon và các khối lặp. Các lớp tĩnh và an toàn luồng là khái niệm dễ hiểu nhất.) – dotnetdev

+0

IMHO, điều quan trọng là phải làm rõ rằng ngay cả trong các ngoại lệ được liệt kê, biến cục bộ là _still_ duy nhất cho mỗi cuộc gọi đến phương thức. Tức là, trong khi chúng có thể được truy cập bên ngoài ngữ cảnh của phương thức, thậm chí có khả năng theo cách không an toàn, chúng vẫn sẽ an toàn theo luồng so với biến _same_ cục bộ trong ngữ cảnh của lệnh _different_ đến cùng phương thức . –

5

Câu lệnh của bạn có hai phần riêng biệt - một cuộc gọi chức năng và một bài tập.

Bài tập là chủ đề an toàn, vì biến là cục bộ. Mỗi lời gọi khác nhau của phương thức này sẽ có phiên bản riêng của biến cục bộ, mỗi biến được lưu trữ trong một khung ngăn xếp khác nhau ở một vị trí khác trong bộ nhớ.

Lệnh gọi getFromDb() có thể hoặc không thể là luồng an toàn - tùy thuộc vào việc triển khai.

2

Miễn là biến cục bộ thành phương pháp an toàn chỉ. Nếu đó là một biến tĩnh, thì nó sẽ không được mặc định.

class Example 
{ 
    static int var1; //not thread-safe 

    public void Method1() 
    { int var2; //thread-safe 
    } 
} 
1

Trong khi int i của bạn là an toàn, toàn bộ vỏ máy của bạn có thể không phải là chỉ an toàn.Int i của bạn, như bạn đã nói, thread an toàn bởi vì mỗi thread có dấu vết stack riêng của mình và do đó mỗi thread có i của riêng mình. Tuy nhiên, chuỗi của bạn đều chia sẻ cùng một cơ sở dữ liệu, do đó truy cập cơ sở dữ liệu của bạn không phải là luồng an toàn. Bạn cần phải đồng bộ hóa đúng cách truy cập cơ sở dữ liệu của bạn để đảm bảo rằng mỗi luồng sẽ chỉ xem cơ sở dữ liệu vào đúng thời điểm.

Như thường lệ với đồng thời và đa luồng, bạn không cần phải đồng bộ hóa trên DB của mình nếu bạn chỉ đọc thông tin. Bạn cần phải đồng bộ hóa ngay sau khi hai chủ đề sẽ cố gắng đọc/ghi cùng một tập hợp các thông tin từ DB của bạn.

1

tôi sẽ là "chủ đề an toàn" vì mỗi chủ đề sẽ có bản sao riêng của tôi trên ngăn xếp như bạn đề xuất. Câu hỏi thực sự sẽ là nội dung của getFromDb() thread an toàn?

1

i là biến cục bộ để không phải trạng thái được chia sẻ.

Nếu getFromDb của bạn() được đọc từ, chẳng hạn, một chuỗi oracle hoặc một máy chủ sql autoincrement lĩnh vực thì db đang chăm sóc cho đồng bộ (trong hầu hết các tình huống, trừ sao chép/phân phối DBS), do đó bạn có thể có thể trở lại một cách an toàn dẫn đến bất kỳ chuỗi cuộc gọi nào. Nghĩa là, DB đảm bảo rằng mọi cuộc gọi getFromDB() sẽ nhận được một giá trị khác.

An toàn chủ đề thường là một chút công việc - việc thay đổi loại biến sẽ hiếm khi giúp bạn an toàn luồng vì nó phụ thuộc vào cách chủ đề của bạn sẽ truy cập dữ liệu. Bạn có thể tiết kiệm cho mình một số nhức đầu bằng cách làm lại thuật toán của bạn để nó sử dụng một hàng đợi mà tất cả người tiêu dùng đồng bộ hóa thay vì cố gắng dàn dựng một loạt các khóa/màn hình. Hoặc tốt hơn là làm cho thuật toán khóa miễn phí nếu có thể.

1

i là chủ đề an toàn về cú pháp. Nhưng khi bạn gán các giá trị của biến instance, giá trị trả về của phương thức instance cho i, thì dữ liệu được chia sẻ được điều khiển bởi nhiều luồng.

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