2013-09-04 33 views
10

Điều gì xảy ra với khóa trong IOS bằng @synchronized() khi chúng tôi gọi dispatch_async() trong khối.khối được đồng bộ hóa và dispatch_async

Đối với ví dụ:

id myID 
-(void) foobar 
{ 
    @synchronized(myID){ 
     dispatch_async(){ //do stuff with myID}; 
    } 
} 

là khóa vẫn có giá trị trong phạm vi các cuộc gọi dispatch_async? Hoặc quan trọng hơn là có bất kỳ hạn chế nào khi sử dụng một cuộc gọi @synchronized() khác bên trong dispatch_async()?

+0

Bạn đang cố gắng đạt được điều gì? – Wain

+0

BTW, tôi có đúng với giả định rằng bạn đang _không phục hồi 'myID' tại bất kỳ thời điểm nào không? Khối '@ synchronized' là duy nhất cho cá thể cụ thể của đối tượng được trỏ đến bởi' myID', không phải là biến nói chung. – Rob

Trả lời

3

Khóa ở đó sẽ chỉ ngăn hai khối khác nhau được gửi đi cùng một lúc. Tuy nhiên, chúng được gửi đi không đồng bộ, vì vậy chúng có thể được thực hiện sau đó hoặc có thể được thực hiện tùy ý trong tương lai. Cuộc gọi công văn cũng sẽ không chờ họ hoàn thành.

Vì vậy, nội dung bên trong khối không được đồng bộ hóa. Các tùy chọn để đạt được điều đó với những thay đổi tối thiểu là một công văn đồng bộ hoặc chỉ @synchronizing trong khối.

Tùy thuộc vào những gì bạn đang làm, ý tưởng tốt nhất có thể là thiết lập hàng đợi công văn nối tiếp và gửi khối của bạn lên đó.

8

Giả sử bạn đang cố gắng đồng bộ hóa tương tác với đối tượng myID này trong hàng đợi nền, bạn muốn nó theo cách khác xung quanh, khóa bên trong khối được gửi đi. Ngay bây giờ bạn có:

@synchronized(myID) { 
    dispatch_async(queue, ^{ 
     // do stuff with myID 
    }); 
} 

Đó là đồng bộ hóa quá trình thêm khối cử đến hàng đợi của bạn, nhưng không không đồng bộ hóa những gì bạn đang làm trong nền. Tôi nghi ngờ đó không phải là ý của bạn.

Bạn có dự định:

dispatch_async(queue, ^{ 
    @synchronized(myID) { 
     // do stuff with myID 
    } 
}); 

Nó trông rất giống nhau, nhưng kết quả trong một hành vi hoàn toàn khác nhau. Bây giờ, công việc được gửi đến hàng đợi nền đang được đồng bộ hóa.

Là một tinh tế hơn nữa, nếu điều này cử khối có thể là chậm (và tôi cho rằng nó có thể được), sau đó bạn có thể muốn hạn chế @synchronized khối càng nhiều càng tốt:

dispatch_async(queue, ^{ 

    // do slow stuff in preparation for interacting with `myID` 

    @synchronized(myID) { 
     // quickly do stuff with myID 
    } 

    // do anything else here 
}); 

Nếu bạn làm tất cả các khối nền trong một khối @synchronized, bạn có thể đánh bại toàn bộ mục đích để gửi nó đến nền, cụ thể là để giảm thiểu tác động lên hàng đợi chính. Buổi biểu diễn cuối cùng này giảm nhẹ vấn đề đó. Theo quan sát cuối cùng, nếu bạn có hàng đợi nối tiếp (hoặc hàng đợi đồng thời không phải là toàn cầu mà bạn cập nhật bằng một rào chắn), nó thường được sử dụng như một kỹ thuật giúp loại bỏ hoàn toàn nhu cầu về khóa, miễn là tất cả các cập nhật và yêu cầu cho myID được gửi đến hàng đợi đó. Xem Eliminating Lock-Based Code trong Hướng dẫn lập trình đồng thời .

+0

Khi bạn nói "giảm thiểu tác động lên hàng đợi chính", nghĩa là quá trình nền sẽ mất nhiều thời gian hơn, phải không? Công việc vẫn đang được thực hiện trong hàng đợi nền và sẽ không có nghĩa là chặn giao diện người dùng. – Ixx

+0

@Ixx - Không, quan điểm của tôi là nếu (a) bạn làm điều gì đó tốn thời gian bên trong một khối '@ synchronized' trên một chuỗi nền; và (b) nếu chủ đề chính cũng cần truy cập 'myID' (và do đó sẽ phải sử dụng' @ synchronized'), nền '@ synchronized' của bạn có thể dễ dàng chặn luồng chính, đánh bại mục đích gửi đi công cụ cho một hàng đợi nền hoàn toàn. Vì vậy, khi chủ đề nền phải thực hiện '@ synchronized', hãy đảm bảo bạn vào và ra càng nhanh càng tốt, giữ các công cụ tốn thời gian bên ngoài khối' @ synchronized', nếu bạn có thể. – Rob

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