【问题标题】:Simple Thread Synchronization简单的线程同步
【发布时间】:2010-10-12 17:25:15
【问题描述】:

我需要一个简单的“一次一个”锁定一段代码。考虑可以从多个线程运行的函数func

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

我需要确保operation1operation2 始终“一起”运行。使用 C#,我会在这两个调用周围使用一个简单的 lock 块。什么是 C++/Win32/MFC 等价物?

大概是某种Mutex

【问题讨论】:

    标签: c++ winapi mfc


    【解决方案1】:

    修复上面的Michael solution

    Michael 解决方案非常适合 C 应用程序。但是当在 C++ 中使用时,由于异常的可能性,不鼓励这种风格。如果 operation1 或 operation2 发生异常,则临界区将不会正确离开,所有其他线程将阻塞等待。

    // 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();
    }
    

    【讨论】:

    • 编程艺术。十分优雅。更容易区分关键部分块并且不太可能出错。 :-)
    • 有史以来最好的答案。 :)
    【解决方案2】:

    Critical 部分可以工作(它们比互斥锁更轻。) InitializeCriticalSection、EnterCriticalSection、LeaveCriticalSection 和 DeleteCriticalSection 是要在 MSDN 上查找的函数。

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

    编辑: 临界区比互斥锁快,因为临界区主要是用户模式原语——在非竞争获取的情况下(通常是常见情况),内核没有系统调用,并且获取需要几十个周期。内核切换更昂贵(大约数百个周期)。调用内核的唯一时间关键部分是为了阻塞,这涉及等待内核原语(互斥锁或事件)。获取互斥体总是需要调用内核,因此速度要慢几个数量级。 但是,临界区只能用于同步一个进程中的资源。为了跨多个进程同步,需要互斥体。

    【讨论】:

    • 到目前为止是正确的,但据我所知,CriticalSections 在内部使用互斥锁,因此没有性能优势。
    • 然后为了异常安全,您可以将 cs 包装到一个类中;见 RAII。
    • (因为问题是关于 C++ 的。)
    • Nils - 更新了为什么关键部分更快的答案。它们不仅仅是互斥锁的包装器。
    • 您可能应该将其包装在一个对象中。使用这样的 C 代码不是异常安全的。
    【解决方案3】:

    最好的方法是使用临界区,使用 EnterCriticalSection 和 LeaveCriticalSection。唯一棘手的部分是您需要首先使用 InitializeCriticalSection 初始化临界区。如果此代码在一个类中,则将初始化放在构造函数中,并将 CRITICAL_SECTION 数据结构作为类的成员。如果代码不是类的一部分,您可能需要使用全局或类似的东西来确保它被初始化一次。

    【讨论】:

      【解决方案4】:
      1. 使用 MFC:

        1. 定义一个同步对象。 (多文本或关键部分)

          1.1 如果属于不同进程的多个线程进入 func() 然后使用 CMutex。

          1.2。如果同一进程的多个线程进入 func() 则使用 CCriticalSection。

        2. CSingleLock 可用于简化同步对象的使用。

      假设我们已经定义了临界区

       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();
          }
      

      编辑:参考 MSDN 中的 VC++ 文章:Multithreading with C++ and MFC ClassesMultithreading: How to Use the Synchronization Classes

      【讨论】:

        【解决方案5】:

        你可以试试这个:

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

        【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-10-25
        • 1970-01-01
        • 2015-02-15
        • 2017-09-14
        相关资源
        最近更新 更多