代码之家  ›  专栏  ›  技术社区  ›  Mahesh Jagtap

在C++中同步线程

  •  -3
  • Mahesh Jagtap  · 技术社区  · 6 年前

    我有三根线-第一根线印的是“好”,第二根线印的是“早上”,第三根线印的是“全部”。我该如何使用这些线来持续地在屏幕上打印早上好?

    2 回复  |  直到 6 年前
        1
  •  0
  •   PhoenixBlue    6 年前

    首先,你只是在浪费资源。

    然而,假设你真的需要这样做来完成比打印单词更重要的事情,这里有一个建议:

    创建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
  •  0
  •   flu    6 年前

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

    • working =其中一个线程正在工作
    • ready_for_task1 =轮到任务1开始工作
    • ready_for_task2 =轮到任务2开始工作
    • ready_for_task3 =轮到任务3开始工作

    总的想法是在这些状态中循环:

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