2009-03-11 36 views
6

Tôi cần một khóa "một lần" đơn giản trên một phần mã. Hãy xem xét các chức năng func mà có thể chạy từ nhiều chủ đề:Đồng bộ hóa chủ đề đơn giản

void func() 
{ 
    // locking/mutex statement goes here 
    operation1(); 
    operation2(); 
    // corresponding unlock goes here 
    operation3(); 
} 

tôi cần phải chắc chắn rằng operation1operation2 luôn chạy "cùng nhau". Với C# tôi sẽ sử dụng một khối đơn giản lock xung quanh hai cuộc gọi này. Tương đương với C++/Win32/MFC là gì?

Có lẽ một số loại Mutex?

Trả lời

19

Các phần quan trọng sẽ hoạt động (chúng có trọng lượng nhẹ hơn mà mutexes.) InitializeCriticalSection, EnterCriticalSection, LeaveCriticalSection và DeleteCriticalSection là các chức năng tìm kiếm trên MSDN.

void func() 
{ 
    // cs previously initialized via InitializeCriticalSection 
    EnterCriticalSection(&cs); 
    operation1(); 
    operation2(); 
    LeaveCriticalSection(&cs); 
    operation3();} 
} 

EDIT: Phần quan trọng là nhanh hơn so với mutexes từ bộ phận quan trọng chủ yếu là chế độ người dùng nguyên thủy - trong trường hợp của một Acquire uncontended (thường là trường hợp phổ biến) không có cuộc gọi hệ thống vào hạt nhân, và mua mất theo thứ tự của hàng chục chu kỳ. Một chuyển đổi hạt nhân là đắt hơn (theo thứ tự của hàng trăm chu kỳ). Phần thời gian quan trọng chỉ gọi vào hạt nhân là để chặn, trong đó bao gồm chờ đợi trên một nguyên thủy hạt nhân, (hoặc mutex hoặc sự kiện). Nhận được một mutex luôn luôn liên quan đến một cuộc gọi vào hạt nhân, và do đó đơn đặt hàng của cường độ chậm hơn. Tuy nhiên, các phần quan trọng chỉ có thể được sử dụng để đồng bộ hóa tài nguyên trong một quy trình. Để đồng bộ hóa qua nhiều quy trình, cần có một mutex.

+0

Đúng cho đến nay, nhưng theo như tôi biết CriticalSections sử dụng mutexes nội bộ, do đó không có lợi ích hiệu suất. –

+0

Và sau đó cho an toàn ngoại lệ, bạn có thể bọc cs vào một lớp; xem RAII. – Reunanen

+0

(Vì câu hỏi là về C++.) – Reunanen

2

Bạn có thể thử này:

void func() 
{ 
    // See answer by Sasha on how to create the mutex 
    WaitForSingleObject (mutex, INFINITE); 
    operation1(); 
    operation2(); 
    ReleaseMutex(mutex); 
    operation3(); 
} 
+0

WaitForSingleObject chậm hơn. CriticalSections có thể mất một số lượng spin và sẽ quay trong một thời gian trước khi rơi qua WaitForSingleObject. xem http://msdn.microsoft.com/en-us/library/ms683476 (VS.85).aspx InitializeCriticalSectionAndSpinCount Function –

6

Phương pháp tốt nhất là sử dụng một phần quan trọng, sử dụng EnterCriticalSection và LeaveCriticalSection. Phần ticky duy nhất là bạn cần phải khởi tạo một phần quan trọng đầu tiên với InitializeCriticalSection. Nếu mã này nằm trong một lớp, hãy đặt khởi tạo trong hàm tạo và cấu trúc dữ liệu CRITICAL_SECTION làm thành viên của lớp. Nếu mã không phải là một phần của một lớp, bạn cần phải sử dụng toàn cầu hoặc một cái gì đó tương tự để đảm bảo nó được khởi tạo một lần.

6
  1. sử dụng MFC:

    1. Xác định một đối tượng đồng bộ hóa. (Phần ẩn hoặc phần quan trọng)

      1.1 Nếu có nhiều luồng thuộc quá trình khác nhau, hãy nhập func() rồi sử dụng CMutex.

      1.2. Nếu nhiều luồng của cùng một quá trình nhập func() thì sử dụng CCriticalSection.

    2. CSingleLock có thể được sử dụng để giảm thiểu việc sử dụng các đối tượng đồng bộ hóa.

phép nói rằng chúng tôi đã xác định phần quan trọng

CCriticalSection m_CriticalSection; 
    void func() 
    { 
     // locking/mutex statement goes here 
     CSingleLock aLock(&m_CriticalSection, **TRUE**); 
     // TRUE indicates that Lock aquired during aLock creation. 
     // if FALSE used then use aLock.Lock() for locking. 

     operation1(); 
     operation2(); 
      // corresponding unlock goes here 
      aLock.Unlock(); 
     operation3(); 
    } 

EDIT: Hãy tham khảo bài viết VC++ từ MSDN: Multithreading with C++ and MFC ClassesMultithreading: How to Use the Synchronization Classes

25

Sửa Michael solution trên.

Giải pháp Michael hoàn hảo cho các ứng dụng C. Nhưng khi được sử dụng trong C++, kiểu này không được khuyến khích vì tính khả dụng của các ngoại lệ. Nếu một ngoại lệ xảy ra trong operation1 hoặc operation2 thì phần quan trọng sẽ không được chính xác trái và tất cả các luồng khác sẽ chặn chờ đợi.

// Perfect solutiuon for C applications 
void func() 
{ 
    // cs previously initialized via InitializeCriticalSection 
    EnterCriticalSection(&cs); 
    operation1(); 
    operation2(); 
    LeaveCriticalSection(&cs); 
    operation3();} 
} 

// A better solution for C++ 
class Locker 
{ 
    public: 
    Locker(CSType& cs): m_cs(cs) 
    { 
     EnterCriticalSection(&m_cs); 
    } 
    ~Locker() 
    { 
     LeaveCriticalSection(&m_cs); 
    } 
    private: 
     CSType& m_cs; 
} 
void func() 
{ 
    // cs previously initialized via InitializeCriticalSection 
    { 
     Locker lock(cs); 
     operation1(); 
     operation2(); 
    } 
    operation3(); 
} 
+0

+1 RAII thực hành tốt nhất .. – deepdive

+0

Nghệ thuật lập trình. Rất thanh lịch. Dễ dàng phân biệt các khối phần quan trọng và ít có khả năng phạm sai lầm. :-) – StanE

+0

Câu trả lời hay nhất từ ​​trước tới nay. :) – Mak

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