2009-08-25 3 views
6

Hãy nói rằng tôi có đoạn mã sauChủ đề có đang chờ khóa FIFO không?

static class ... 
{ 
    static object myobj = new object(); 

    static void mymethod() 
    { 
     lock(myobj) 
     { 
      // my code.... 
     } 
    } 
} 

Sau đó, chúng ta hãy nói rằng trong khi thread1 có khóa thread2 cố gắng chạy MyMethod. Nó sẽ chờ đợi cho khóa được phát hành hoặc ném một ngoại lệ?

Nếu nó chờ, trật tự được đảm bảo sao cho các chủ đề bổ sung có trong FIFO không?

Trả lời

8

Cập nhật câu trả lời của tôi: Chúng được xếp hàng đợi, nhưng thứ tự không được đảm bảo là FIFO.

Kiểm tra liên kết này: http://www.albahari.com/threading/part2.aspx

+4

Không nhất thiết phải xem: http://stackoverflow.com/questions/961869/is-there-a-synchronization-class-that-guarantee-fifo-order-in-c/961904 –

-1

Nó sẽ chờ, và họ sẽ không theo thứ tự.

Tùy thuộc vào nhu cầu của bạn, bạn có thể có hiệu suất hơn nếu bạn nhìn vào một cái gì đó giống như một ReaderWriterLock hay cái gì khác hơn là chỉ lock

+1

Chúng không giống nhau gọi món. –

3

Nó không phải là rõ ràng từ mã của bạn như thế nào myobj lấy được hiển thị bên trong mymethod. Có vẻ như var myobj là biến ngăn xếp cục bộ tại phạm vi khai báo (kể từ là var). Trong trường hợp đó, có thể là mỗi luồng sẽ có một phiên bản riêng biệt của nó và mymethod sẽ không chặn.

Cập nhật

Về lập luận toàn FIFO, một số thông tin nền là cần thiết: CLR không cung cấp syncronization. Đây là máy chủ CLR cung cấp dịch vụ này cho thời gian chạy CLR. Máy chủ thực hiện IHostSyncManager và các giao diện khác và cung cấp các nguyên bản đồng bộ hóa khác nhau. Điều này có vẻ không liên quan vì máy chủ lưu trữ phổ biến nhất là máy chủ ứng dụng điển hình (tức là bạn biên dịch vào và exe) và điều này làm cho tất cả đồng bộ hóa với hệ điều hành (sách nguyên thủy cũ của bạn trong Win32 API). Tuy nhiên có ít nhất hai lưu trữ lớn hơn evironments: ASP.Net một (Tôi không chắc chắn những gì điều này không) và SQL Server. Những gì tôi có thể nói chắc chắn là SQL Server cung cấp tất cả các nguyên thủy trên đỉnh của SOS (về cơ bản là một hệ điều hành người dùng), không bao giờ chạm vào nguyên thủy của hệ điều hành, và các nguyên thủy SOS không công bằng bằng thiết kế để tránh các đoàn tàu khóa (ví dụ: guranteed no FIFO). Khi liên kết trong phản ứng khác đã được chỉ ra, các nguyên thủy hệ điều hành đã bắt đầu cũng để cung cấp hành vi không công bằng, cho cùng một lý do tránh các đoàn tàu khóa.

Để biết thêm thông tin về đoàn khóa bạn nên đọc các bài viết Rick Vicik tại Designing Applications for High Performance:

Khóa Convoy

khóa FIFO đảm bảo sự công bằng và tiến về phía trước tại các chi phí của gây đoàn khóa . Thuật ngữ ban đầu có nghĩa là một số đề thực hiện cùng một phần của mã như một nhóm dẫn đến va chạm cao hơn nếu họ được phân phối ngẫu nhiên khắp mã (giống như xe ô tô được nhóm lại thành các gói bằng đèn giao thông).Hiện tượng cụ thể mà tôi đang nói đến là tồi tệ hơn bởi vì khi nó hình thành việc chuyển quyền sở hữu khóa tiềm ẩn giữ các chủ đề trong khóa bước.

Để minh họa, hãy xem ví dụ trong đó một sợi có khóa và được đặt trước trong khi giữ khóa. Kết quả là tất cả các chủ đề khác sẽ xếp chồng lên danh sách chờ cho khóa đó. Khi chủ đề được đề cập trước (khóa chủ sở hữu tại thời điểm này) được chạy lại và nhả khóa, nó tự động chuyển quyền sở hữu của khóa sang chuỗi đầu tiên trong danh sách chờ . Chủ đề đó có thể không chạy cho một thời gian, nhưng đồng hồ “giữ thời gian” đang được đánh dấu. Chủ sở hữu trước thường yêu cầu các khóa lần nữa trước khi danh sách chờ đợi sẽ bị xóa ra, việc duy trì đoàn công voa

+0

bạn là chính xác, nó là một đối tượng tĩnh trong một đối tượng tĩnh, tôi đã viết quá nhanh. Sẽ sửa nó ngay bây giờ – Matt

0

Windows và CLR cố gắng hết sức mình để đảm bảo tính công bằng (thứ tự FIFO) của sự chờ đợi. Tuy nhiên, có một số tình huống mà thứ tự của các chủ đề chờ đợi trên một khóa có thể được thay đổi, chủ yếu là xoay quanh chờ đợi cảnh báo và tất cả các khóa thread CLR đặt thread trong trạng thái cảnh báo.

Đối với tất cả các mục đích thực tế, bạn có thể giả định rằng thứ tự sẽ là FIFO; tuy nhiên, hãy lưu ý vấn đề này.

1

Một ví dụ đơn giản cho chúng tôi biết rằng trật tự không được bảo đảm là FIFO

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading; 
using System.Diagnostics; 


namespace ConsoleApplication 
{ 
    class Program 
    { 
     private static Info info = new Info(); 

     static void Main(string[] args) 
     { 
      Thread[] t1 = new Thread[5]; 
      for (int i = 0; i < 5; i++) 
      { 
       t1[i] = new Thread(info.DoWork); 
      } 

      Thread[] t2 = new Thread[5]; 
      for (int i = 0; i < 5; i++) 
      { 
       t2[i] = new Thread(info.Process); 
      } 

      for (int i = 0; i < 5; i++) 
      { 
       t1[i].Start(); 
       t2[i].Start(); 
      } 

      Console.ReadKey(); 
     } 
    } 

    class Info 
    { 
     public object SynObject = new object(); 

     public void DoWork() 
     { 
      Debug.Print("DoWork Lock Reached: {0}", Thread.CurrentThread.ManagedThreadId); 
      lock (this.SynObject) 
      { 
       Debug.Print("Thread Lock Enter: {0}", Thread.CurrentThread.ManagedThreadId); 
       Thread.Sleep(5000); 
       Debug.Print("Thread Lock Exit: {0}", Thread.CurrentThread.ManagedThreadId); 
      } 
     } 

     public void Process() 
     { 
      Debug.Print("Process Lock Reached: {0}", Thread.CurrentThread.ManagedThreadId); 
      lock (this.SynObject) 
      { 
       Debug.Print("Process Lock Enter: {0}", Thread.CurrentThread.ManagedThreadId); 
       Thread.Sleep(5000); 
       Debug.Print("Process Lock Exit: {0}", Thread.CurrentThread.ManagedThreadId); 
      } 
     } 
    } 
} 
using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading; 
using System.Diagnostics; 


namespace ConsoleApplication 
{ 
    class Program 
    { 
     private static Info info = new Info(); 

     static void Main(string[] args) 
     { 
      Thread[] t1 = new Thread[5]; 
      for (int i = 0; i < 5; i++) 
      { 
       t1[i] = new Thread(info.DoWork); 
      } 

      Thread[] t2 = new Thread[5]; 
      for (int i = 0; i < 5; i++) 
      { 
       t2[i] = new Thread(info.Process); 
      } 

      for (int i = 0; i < 5; i++) 
      { 
       t1[i].Start(); 
       t2[i].Start(); 
      } 

      Console.ReadKey(); 
     } 
    } 

    class Info 
    { 
     public object SynObject = new object(); 

     public void DoWork() 
     { 
      Debug.Print("DoWork Lock Reached: {0}", Thread.CurrentThread.ManagedThreadId); 
      lock (this.SynObject) 
      { 
       Debug.Print("Thread Lock Enter: {0}", Thread.CurrentThread.ManagedThreadId); 
       Thread.Sleep(5000); 
       Debug.Print("Thread Lock Exit: {0}", Thread.CurrentThread.ManagedThreadId); 
      } 
     } 

     public void Process() 
     { 
      Debug.Print("Process Lock Reached: {0}", Thread.CurrentThread.ManagedThreadId); 
      lock (this.SynObject) 
      { 
       Debug.Print("Process Lock Enter: {0}", Thread.CurrentThread.ManagedThreadId); 
       Thread.Sleep(5000); 
       Debug.Print("Process Lock Exit: {0}", Thread.CurrentThread.ManagedThreadId); 
      } 
     } 
    } 
} 

Execution sẽ procede một cái gì đó như thế này

Process Lock Reached: 15 
Process Lock Enter: 15 
DoWork Lock Reached: 12 
Process Lock Reached: 17 
DoWork Lock Reached: 11 
DoWork Lock Reached: 10 
DoWork Lock Reached: 13 
DoWork Lock Reached: 9 
Process Lock Reached: 18 
Process Lock Reached: 14 
Process Lock Reached: 16 
Process Lock Exit: 15 
Thread Lock Enter: 9 
Thread Lock Exit: 9 
Process Lock Enter: 14 
Process Lock Exit: 14 
Thread Lock Enter: 10 
Thread Lock Exit: 10 
Thread Lock Enter: 11 
Thread Lock Exit: 11 
Process Lock Enter: 16 
Process Lock Exit: 16 
Thread Lock Enter: 12 
Thread Lock Exit: 12 
Process Lock Enter: 17 
Process Lock Exit: 17 
Thread Lock Enter: 13 
Thread Lock Exit: 13 
Process Lock Enter: 18 
Process Lock Exit: 18 

Như bạn ca thấy quá trình khóa tầm là khác nhau mà khóa đi vào.