【问题标题】:Synchronize threads in C++在 C++ 中同步线程
【发布时间】:2018-10-24 10:05:36
【问题描述】:

我有三个线程 - Thread1 打印“Good”,Thread2 打印“Morning”,Thread3 打印“All”。如何使用这些线程在屏幕上持续打印“Good Morning All”?

【问题讨论】:

  • 你不知道。如果您希望以固定的顺序执行内容,那么使用多个线程是浪费资源
  • @user463035818 你是对的,但是 OP 的要求听起来像是普通家庭作业的变体。
  • @SolomonSlow 再想一想……我想练习的重点是同步而不是线程本身

标签: c++ multithreading


【解决方案1】:

一方面,您只是在浪费资源。

但是,假设您确实需要它来完成比打印文字更重要的事情,这里有一个建议:

创建 3 个互斥锁 (pthread_mutex)

pthread_mutex_t m_Good, m_Morning, m_all;
pthread_mutex_init(&m_Good, NULL);
pthread_mutex_init(&m_Morning, NULL);
pthread_mutex_init(&m_All, NULL);

锁定最后两个互斥锁

pthread_mutex_lock(&m_Morning);
pthread_mutex_lock(&m_All);

在第一个线程中打印其消息,然后解锁第二个互斥锁。

while(true){
    if(pthread_mutex_lock(&m_Good)==0){
         printf("GOOD ");
         pthread_mutex_unlock(&m_Morning);
         pthread_mutex_lock(&m_Good);
    }
}
  • 第二个线程打印消息,锁定其互斥体并解锁第三个
  • 第三个线程打印它的消息,解锁第一个互斥锁并锁定第三个互斥锁

【讨论】:

    【解决方案2】:

    这是一个简单的无锁实现,用于强制线程顺序执行。它使用一个原子状态变量,可以表示四种可能的状态:

    • working = 其中一个线程正在工作
    • ready_for_task1 = 轮到 task1 开始工作了
    • ready_for_task2 = 轮到 task2 开始工作了
    • ready_for_task3 = 轮到 task3 开始工作了

    一般的想法是循环通过这些状态:

    ready_for_task1 ->
    working ->
    ready_for_task2 ->
    working ->
    ready_for_task3 ->
    working ->
    ready_for_task1 ->
    ...
    

    第一部分,定义状态,声明全局原子状态,并定义一个执行状态转换的守卫类。守卫的守卫构造函数将通过原子地检查其就绪状态并将状态切换为工作来“忙碌”等待。守卫析构函数会将状态设置为下一个任务的就绪状态。

    #include <stdio.h>
    #include <stdlib.h>
    #include <pthread.h>
    #include <atomic>
    
    enum State { ready_for_task1, ready_for_task2, ready_for_task3, working };
    
    static std::atomic< State > state_;
    
    class TransitionGuard {
    public:
        TransitionGuard(State start, State finish) : finish_(finish) {
            State expecting = start;
            while( !state_.compare_exchange_weak( expecting, working ) ) {
                expecting = start;
                asm("pause");
            }
        }
    
        ~TransitionGuard() {
            state_.store( finish_ );
        }
    private:
        const State finish_;
    };
    

    然后每个线程运行自己的循环,在各自的转换保护下打印它们的单词。

    void * task1( void * data )
    {
        while( true ) {
            TransitionGuard guard( ready_for_task1, ready_for_task2 );
            printf( "Good" );
        }
    }
    
    void * task2( void * data)
    {
        while( true ) {
            TransitionGuard guard( ready_for_task2, ready_for_task3 );
            printf( " Morning" );
        }
        return NULL;
    }
    
    void * task3( void * data)
    {
        while( true ) {
            TransitionGuard guard( ready_for_task3, ready_for_task1 );
            printf( " All\n" );
        }
        return NULL;
    }
    

    最后,您需要在创建线程之前初始化状态。

    int main( int argc, const char ** argv )
    {
        state_ = ready_for_task1;
        pthread_t thread1, thread2, thread3;
    
        if( pthread_create( &thread1, NULL, task1, NULL ) )
        {
            fprintf( stderr, "thread1 failed to start\n" );
            exit(EXIT_FAILURE);
        }
    
        if( pthread_create( &thread2, NULL, task2, NULL ) )
        {
            fprintf( stderr, "thread2 failed to start\n" );
            exit(EXIT_FAILURE);
        }
    
        if( pthread_create( &thread3, NULL, task3, NULL ) )
        {
            fprintf( stderr, "thread3 failed to start\n" );
            exit(EXIT_FAILURE);
        }
    
        pthread_join( thread1, NULL );
        pthread_join( thread2, NULL );
        pthread_join( thread3, NULL );
    
        fprintf( stderr, "threads joined. exiting.\n" );
        exit(EXIT_SUCCESS);
    }
    

    【讨论】:

      猜你喜欢
      • 2015-08-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-04-01
      • 2011-06-15
      • 2011-12-28
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多