2012-01-04 22 views
12

Tôi đã hiểu chính xác rằng tất cả các luồng có sao chép các biến của phương thức trong ngăn xếp của riêng chúng sao cho không có vấn đề gì khi một phương thức tĩnh được gọi từ các luồng khác nhau?có thể có các vấn đề tương tranh khi sử dụng lớp C# chỉ với các phương thức tĩnh và không có biến nào không?

+0

Nếu đó là ràng buộc chặt chẽ - * có thể *. Nhưng nó không giống như một phương pháp rất thú vị. – Yuck

+0

Tôi tin rằng các vấn đề sẽ xảy ra khi làm ngược lại ví dụ bạn có thể có một lớp công khai cũng có quyền truy cập vào các phương thức tĩnh, bạn có thể đưa ra một ví dụ về mã thể hiện chính xác sự nhầm lẫn của bạn là gì không ..? – MethodMan

+0

Bạn có thể thấy điều này hữu ích: http://csharpindepth.com/Articles/General/Singleton.aspx – David

Trả lời

16

Có và không. Nếu các tham số là các kiểu giá trị, thì có, chúng có các bản sao riêng của chúng. Hoặc nếu kiểu tham chiếu là không thay đổi, thì nó không thể thay đổi được và bạn không có vấn đề gì. Tuy nhiên, nếu các tham số là loại tham chiếu có thể thay đổi, thì vẫn có các vấn đề an toàn chủ đề có thể xảy ra để xem xét với các đối số được truyền vào.

Điều đó có hợp lý không? Nếu bạn chuyển một kiểu tham chiếu làm đối số, thì tham chiếu của nó được truyền theo "giá trị", do đó nó là tham chiếu mới đề cập đến đối tượng cũ. Do đó bạn có thể có hai luồng khác nhau có khả năng thay đổi cùng một đối tượng theo cách không an toàn.

Nếu mỗi trường hợp này được tạo và sử dụng chỉ trong trong chuỗi sử dụng chúng, thì có thể thấp, nhưng tôi chỉ muốn nhấn mạnh rằng chỉ vì bạn đang sử dụng phương pháp tĩnh người dân địa phương/thông số không phải là bảo đảm an toàn chủ đề (giống với trường hợp của khóa học được ghi bởi Chris).

+0

+1 để lưu ý rằng việc sử dụng tĩnh (hoặc thiếu) không đảm bảo bất cứ điều gì - các quy tắc tương tự giữ cho các phương pháp không tĩnh. –

+0

cảm ơn! điều này làm cho công việc của tôi dễ dàng hơn rất nhiều. –

+0

@ChrisShain: Rất đúng, tôi nên đề cập đến điều đó một cách rõ ràng, tôi đã hy vọng nó được ngụ ý. –

2

Không có bảo đảm như vậy trừ khi tất cả các biến là loại tham chiếu hoặc loại giá trị không thay đổi.

Nếu các biến là loại tham chiếu có thể thay đổi, cần phải thực hiện đồng bộ hóa đúng cách.

CHỈNH SỬA: Biến chỉ có thể cần được đồng bộ hóa nếu chúng được chia sẻ giữa các biến thể được khai báo cục bộ không được hiển thị bên ngoài phương thức cần được đồng bộ hóa.

+0

Các tham chiếu có thể thay đổi được khai báo và sử dụng cục bộ không cần đồng bộ hóa. – Tudor

+0

Đúng, sẽ chỉnh sửa tương ứng. –

0

Có, trừ khi phương pháp sử dụng chỉ biến phạm vi địa phương và không có bất kỳ biến gloval, vì vậy không có cách nào bất kỳ phương pháp có thể ảnh hưởng đến trạng thái của bất kỳ đối tượng, nếu đây là true, bạn không có vấn đề gì khi sử dụng nó trong đa luồng. Tôi sẽ nói, thậm chí, trong điều kiện này, static họ có hay không, không liên quan.

0

Nếu chúng là biến cục bộ theo phương pháp thì có, bạn không có gì phải lo lắng. Chỉ cần đảm bảo rằng bạn không truyền tham số bằng cách tham chiếu hoặc truy cập các biến toàn cầu và thay đổi chúng trong các luồng khác nhau. Thế thì bạn sẽ gặp rắc rối.

0

static phương pháp có thể tham chiếu đến dữ liệu trong các trường static - trong lớp học hoặc ngoài trường - có thể không phải là chủ đề an toàn.

Vì vậy, cuối cùng câu trả lời cho câu hỏi của bạn là "không", bởi vì có thể có vấn đề, mặc dù thường thì sẽ không có.

0

Hai luồng vẫn có thể hoạt động trên cùng một đối tượng hoặc đối tượng được truyền vào các phương thức trên các chủ đề khác nhau dưới dạng tham số hoặc nếu đối tượng có thể truy cập trên toàn cầu qua Singleton hoặc tương tự tất cả các phiên cược bị tắt.

Đánh dấu

9

Có tôi hiểu một cách chính xác rằng tất cả các chủ đề có bản sao của biến phương pháp trong stack riêng của họ vì vậy sẽ không có vấn đề khi một phương pháp tĩnh được gọi là từ chủ đề khác nhau?

số

Trước hết, đó là sai lầm rằng "tất cả các chủ đề có một bản sao của các biến cục bộ của phương pháp trong ngăn xếp riêng của họ." Biến cục bộ chỉ được tạo trên ngăn xếp khi có thời gian tồn tại ngắn; các biến cục bộ có thể có các vòng đời dài tùy ý nếu chúng là (1) các biến bên ngoài được đóng kín, (2) được khai báo trong một khối lặp, hoặc (3) được khai báo trong một phương thức không đồng bộ.

Trong tất cả các trường hợp, biến cục bộ được tạo bởi kích hoạt một phương thức trên một luồng có thể bị thay đổi bởi nhiều luồng. Làm như vậy không phải là luồng an toàn.

Thứ hai, có rất nhiều vấn đề có thể xảy ra khi gọi các phương thức tĩnh từ các luồng khác nhau. Thực tế là các biến cục bộ đôi khi được cấp phát trên ngăn xếp không kỳ diệu làm cho truy cập vào bộ nhớ chia sẻ bằng các phương thức tĩnh đột nhiên chính xác.

có thể có vấn đề tương tranh khi sử dụng lớp C# chỉ với các phương pháp tĩnh và không có biến nào?

Tôi giả sử bạn có nghĩa là "không có biến tĩnh" và không "không có biến cục bộ".

Tuyệt đối có thể là. Ví dụ, đây là một chương trình không có biến tĩnh, không có phương thức không tĩnh, không có đối tượng nào được tạo ra ngoài luồng thứ hai và một biến cục bộ duy nhất để giữ tham chiếu đến luồng đó. Không có phương pháp nào khác ngoài cctor thực sự là làm bất cứ điều gì ở tất cả. Lỗi chương trình này. Bạn không thể giả định rằng chỉ vì chương trình của bạn đã chết đơn giản mà nó không chứa lỗi luồng!

Tập thể dục cho người đọc: mô tả lý do tại sao chương trình này dường như không chứa khóa thực sự là khóa chết.

class MyClass 
{ 
    static MyClass() 
    { 
     // Let's run the initialization on another thread! 
     var thread = new System.Threading.Thread(Initialize); 
     thread.Start(); 
     thread.Join(); 
    } 

    static void Initialize() 
    { /* TODO: Add initialization code */ } 

    static void Main() 
    { } 
} 

Có vẻ như bạn đang tìm kiếm một số cách kỳ diệu để biết rằng chương trình của bạn không có vấn đề về luồng. Không có cách nào huyền diệu như vậy để biết rằng, ngắn làm cho nó đơn luồng. Bạn sẽ phải phân tích việc bạn sử dụng các luồng và cấu trúc dữ liệu được chia sẻ.

+2

Các ctor tĩnh được đảm bảo hoàn thành trước khi bất kỳ thành viên tĩnh (phương pháp 'Initialize' trong trường hợp này) được phép thực hiện, nhưng ctor đang bận chờ đợi thread đang chờ ctor đó. –

+0

@AlbinSunnanbo: Bạn đã có ý tưởng đúng. Nhưng dĩ nhiên, nếu con tàu được gọi là Khởi tạo mà không sinh ra một luồng, cuộc gọi sẽ được cho phép mặc dù nó là một thành phần tĩnh thực hiện trước khi hàm dựng tĩnh chạy xong. Một cách chính xác hơn để giải quyết vấn đề là: Nếu một luồng thứ hai cố gắng truy cập vào một thành viên tĩnh trong khi cctor đang chạy trên luồng đầu tiên, thì luồng bỏ qua thứ hai gọi hàm cctor và đợi luồng đầu tiên kết thúc trước khi nó truy cập thành viên tĩnh. Nhưng vì trong trường hợp này, luồng đầu tiên đang đợi trên bế tắc thứ hai. –

+0

có vẻ hợp lý. Vấn đề khóa chết không rõ ràng từ [trang MSDN] (http://msdn.microsoft.com/en-us/library/k9x6w0hc.aspx), nhưng [C# specification 17.11] (http: //www.ecma) -international.org/publications/files/ECMA-ST/Ecma-334.pdf) ít nhất là gợi ý bằng cách chú ý "tối đa một lần trong một miền ứng dụng nhất định". –

0

Là phụ lục cho câu trả lời về lý do tại sao các phương pháp tĩnh không nhất thiết phải an toàn theo luồng, đáng xem xét lý do tại sao chúng có thể và tại sao chúng thường là.

Lý do đầu tiên tại sao họ có thể là, tôi nghĩ rằng, các loại trường hợp bạn đang nghĩ đến việc:

public static int Max(int x, int y) 
{ 
    return x > y ? x : y; 
} 

chức năng tinh khiết Đây là thread-an toàn vì không có cách nào cho nó ảnh hưởng đến mã trên bất kỳ chủ đề nào khác, người dân địa phương xy vẫn là địa phương cho các trang web mà họ đang truy cập, không được lưu trữ ở một vị trí được chia sẻ, được ghi lại trong một đại biểu hoặc bằng cách khác rời khỏi bối cảnh thuần túy của địa phương. Nó luôn đáng chú ý, rằng sự kết hợp của các hoạt động an toàn thread có thể không an toàn thread (ví dụ như đọc một thread an toàn cho dù một từ điển đồng thời có một chìa khóa theo sau là một đọc an toàn thread của giá trị cho rằng , không an toàn với luồng vì trạng thái có thể thay đổi giữa hai thao tác an toàn luồng này). Các thành viên tĩnh có xu hướng không phải là thành viên có thể được kết hợp theo những cách không an toàn như vậy để tránh điều này.

Một phương pháp tĩnh cũng có thể đảm bảo riêng thread-an toàn của nó:

public object GetCachedEntity(string key) 
{ 
    object ret; //local and remains so. 
    lock(_cache) //same lock used on every operation that deals with _cache; 
    return _cache.TryGetValue(key, out ret) ? ret : null; 
} 

OR:

public object GetCachedEntity(string key) 
{ 
    object ret; 
    return _cache.TryGetValue(key, out ret) ? ret : null; //_cache is known to be thread-safe in itself! 
} 

Tất nhiên đây này không khác gì so với một thành viên dụ để bảo vệ bản thân chống tham nhũng từ khác chủ đề (bằng cách hợp tác với tất cả các mã khác liên quan đến các đối tượng mà chúng chia sẻ).

Điều đáng chú ý là các thành viên tĩnh có thể an toàn luồng và các thành viên thể hiện không an toàn chỉ là điều rất phổ biến. Hầu hết mọi thành phần tĩnh của FCL đều đảm bảo an toàn luồng trong tài liệu và hầu hết các thành viên không chặn một số lớp được thiết kế đặc biệt để sử dụng đồng thời (thậm chí trong một số trường hợp thành viên thực sự là an toàn luồng).

Lý do là hai lần:

  1. Các loại hoạt động phổ biến nhất là hữu ích cho các thành viên tĩnh là một trong hai chức năng tinh khiết (hầu hết các thành viên tĩnh của lớp Math, ví dụ) hoặc đọc tĩnh đọc các biến chỉ sẽ không bị thay đổi bởi các luồng khác.

  2. Rất khó để mang đồng bộ hóa của riêng bạn đến các thành viên tĩnh của bên thứ ba.

Điểm thứ hai là quan trọng. Nếu tôi có một đối tượng mà các thành viên không an toàn thread, thì giả định rằng các cuộc gọi không ảnh hưởng đến dữ liệu không an toàn được chia sẻ giữa các phiên bản khác nhau (có thể, nhưng gần như chắc chắn là thiết kế xấu), sau đó nếu tôi muốn chia sẻ nó chủ đề, tôi có thể cung cấp khóa của riêng tôi để làm như vậy.

Nếu tuy nhiên, tôi đang xử lý các thành viên tĩnh không an toàn với luồng, tôi sẽ làm điều này khó hơn nhiều. Thật vậy, xem xét rằng tôi có thể chạy đua không chỉ với mã của riêng tôi, nhưng với mã từ các bên khác, nó có thể là không thể. Điều này sẽ làm cho bất kỳ thành viên tĩnh nào như vậy bên cạnh vô dụng.

Trớ trêu thay, lý do các thành viên tĩnh có xu hướng chỉ an toàn không phải là dễ dàng hơn để làm cho chúng như vậy (mặc dù nó bao gồm các chức năng thuần túy), nhưng khó hơn! Thật khó trong thực tế là tác giả của mã phải làm điều đó cho người dùng, bởi vì người dùng sẽ không thể tự làm được.

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