研究条件变量pthread_cond_wait的机制


1条件变量的解释:

  条件变量是利用线程间共享的全局变量进行同步的一种机制,主要包括两个动作:一个线程等待"条件变量的条件成立"而挂起;另一个线程使"条件成立"(给出条件成立信号)。为了防止竞争,条件变量的使用总是和一个互斥锁结合在一起。

int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)

int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime)

  等待条件有两种方式:条件等待pthread_cond_wait()和计时等待pthread_cond_timedwait(),其中计时等待方式如果在给定时刻前条件没有满足,则返回ETIMEDOUT,结束等待,其中abstime以与time()条件变量相同意义的绝对时间形式出现,表示格林尼治时间197011000秒。

  无论哪种等待方式,都必须和一个互斥锁配合,以防止多个线程同时请求pthread_cond_wait()(或pthread_cond_timedwait(),下同)的竞争条件Race Condition)。mutex互斥锁必须是普通锁(PTHREAD_MUTEX_TIMED_NP)或者适应锁(PTHREAD_MUTEX_ADAPTIVE_NP),且在调用pthread_cond_wait()前必须由本线程加锁(pthread_mutex_lock()),而在更新条件等待队列以前,mutex保持锁定状态,并在线程挂起进入等待前解锁。在条件满足从而离开pthread_cond_wait()之前,mutex将被重新加锁,以与进入pthread_cond_wait()前的加锁动作对应。阻塞时处于解锁状态。

  激发条件有两种形式,pthread_cond_signal()激活一个等待该条件的线程,存在多个等待线程时按入队顺序激活其中一个;而pthread_cond_broadcast()则激活所有等待线程。

 

 

2pthread_cond_wait测试

2.1方法:

    在某多线程文件转发协议的代码里加上日志和睡眠时间进行测试。配置TCP_THREAD_NUM=5

 

* 函数名称:InitTcpThread

* 功能描述:创建链路检测的线程和锁

BOOLEAN InitTcpThread()

{

......

    LOG"TEST1 InitTcpThread  gInitCount:%d,TCP_THREAD_NUM:%d.",gInitCount,TCP_THREAD_NUM);

    //等待处理线程池ready ok,只能在一个线程中等待

    pthread_mutex_lock(&gInitLock);

    while (gInitCount < TCP_THREAD_NUM)

    {

        LOG("TEST2 InitTcpThread  gInitCount:%d,TCP_THREAD_NUM:%d.",gInitCount,TCP_THREAD_NUM);

        pthread_cond_wait(&gInitCond, &gInitLock);

        LOG("TEST3 InitTcpThread  gInitCount:%d,TCP_THREAD_NUM:%d.",gInitCount,TCP_THREAD_NUM);

    }

    pthread_mutex_unlock(&gInitLock);

    LOG("TEST4 InitTcpThread  gInitCount:%d,TCP_THREAD_NUM:%d.",gInitCount,TCP_THREAD_NUM);

......

    }

 ......

}

* 函数名称:tcpChkLinkTaskProc

* 功能描述HTTP SA工作线程

VOID tcpChkLinkTaskProc(LPVOID lpPno)

{

......

    sleep(1);

    LOG(" TEST1 tcpChkLinkTaskProc gInitCount:%d.  ",gInitCount);

    //条件变量,通知listening thread

    pthread_mutex_lock(&gInitLock);

    LOG(" TEST2 tcpChkLinkTaskProc gInitCount:%d.  ",gInitCount);

    sleep(1);

    gInitCount++;

    LOG(" TEST3 tcpChkLinkTaskProc gInitCount:%d.  ",gInitCount);

    pthread_cond_signal(&gInitCond);

    LOG(" TEST4 tcpChkLinkTaskProc gInitCount:%d.  ",gInitCount);

    pthread_mutex_unlock(&gInitLock);

    LOG(" TEST5 tcpChkLinkTaskProc gInitCount:%d.  ",gInitCount);

......

}

 

2.2测试日志

18-03-29 12:51:52:189 [TEST1 InitTcpThread  gInitCount:0,TCP_THREAD_NUM:5.]

18-03-29 12:51:52:189 [TEST2 InitTcpThread  gInitCount:0,TCP_THREAD_NUM:5.]

18-03-29 12:51:53:189 [ TEST1 tcpChkLinkTaskProc gInitCount:0.  ]

18-03-29 12:51:53:189 [ TEST1 tcpChkLinkTaskProc gInitCount:0.  ]

18-03-29 12:51:53:189 [ TEST1 tcpChkLinkTaskProc gInitCount:0.  ]

18-03-29 12:51:53:189 [ TEST1 tcpChkLinkTaskProc gInitCount:0.  ]

18-03-29 12:51:53:189 [ TEST2 tcpChkLinkTaskProc gInitCount:0.  ]

18-03-29 12:51:53:190 [ TEST1 tcpChkLinkTaskProc gInitCount:0.  ]

18-03-29 12:51:54:190 [ TEST3 tcpChkLinkTaskProc gInitCount:1.  ]

18-03-29 12:51:54:190 [ TEST4 tcpChkLinkTaskProc gInitCount:1.  ]

18-03-29 12:51:54:190 [ TEST5 tcpChkLinkTaskProc gInitCount:1.  ]

18-03-29 12:51:54:190 [ TEST2 tcpChkLinkTaskProc gInitCount:1.  ]

18-03-29 12:51:55:190 [ TEST3 tcpChkLinkTaskProc gInitCount:2.  ]

18-03-29 12:51:55:190 [ TEST4 tcpChkLinkTaskProc gInitCount:2.  ]

18-03-29 12:51:55:190 [ TEST5 tcpChkLinkTaskProc gInitCount:2.  ]

18-03-29 12:51:55:190 [ TEST2 tcpChkLinkTaskProc gInitCount:2.  ]

18-03-29 12:51:56:191 [ TEST3 tcpChkLinkTaskProc gInitCount:3.  ]

18-03-29 12:51:56:191 [ TEST4 tcpChkLinkTaskProc gInitCount:3.  ]

18-03-29 12:51:56:191 [ TEST5 tcpChkLinkTaskProc gInitCount:3.  ]

18-03-29 12:51:56:191 [ TEST2 tcpChkLinkTaskProc gInitCount:3.  ]

18-03-29 12:51:57:191 [ TEST3 tcpChkLinkTaskProc gInitCount:4.  ]

18-03-29 12:51:57:191 [ TEST4 tcpChkLinkTaskProc gInitCount:4.  ]

18-03-29 12:51:57:191 [ TEST5 tcpChkLinkTaskProc gInitCount:4.  ]

18-03-29 12:51:57:191 [ TEST2 tcpChkLinkTaskProc gInitCount:4.  ]

18-03-29 12:51:58:191 [ TEST3 tcpChkLinkTaskProc gInitCount:5.  ]

18-03-29 12:51:58:191 [ TEST4 tcpChkLinkTaskProc gInitCount:5.  ]

18-03-29 12:51:58:191 [ TEST5 tcpChkLinkTaskProc gInitCount:5.  ]

18-03-29 12:51:58:191 [TEST3 InitTcpThread  gInitCount:5,TCP_THREAD_NUM:5.]

18-03-29 12:51:58:192 [TEST4 InitTcpThread  gInitCount:5,TCP_THREAD_NUM:5.]

18-03-29 12:51:58: [InitTcpThread--Index[0]:host[10.46.181.23] port[5881]]

18-03-29 12:51:58: [InitTcpThread--ListenThreadNum[1] WorkThreadNum[5]]

 

2.3分析

       pthread_cond_wait 内部自带解锁和加锁,在InitTcpThread 创建链路检测的线程和锁函数 调用它之前必须求本线程加锁(pthread_mutex_lock(&gInitLock) ),刚进入 pthread_cond_wait gInitCount =0 ,随后 pthread_cond_wait 解锁 &gInitLock 并等待条件满足。之后,tcpChkLinkTaskProc HTTP SA 工作线程的五个线程以此起来( gInitLock 加锁 gInitCount 自增, pthread_cond_signal(&gInitCond) 发信号给等待线程,gInitLock 解锁),第五个信号发出后InitTcpThread 链路检测的线程里的“gInitCount < TCP_THREAD_NUM ”便不再成立,链路检测线程的代码继续往下走。

你可能感兴趣的:(tech,knowledge,C语言,条件变量,互斥锁,多线程)