三、互斥量与条件变量
互斥量存在的问题:从本质上说互斥量就是一把锁,互斥量串行执行,能确保每次只有一个线程访问。互斥量是线程程序必需的工具,但它们并非万能的。例如,如果线程正在轮询等待共享数据内某个条件出现,那会发生什么呢?它可以重复对互斥对象锁定和解锁,每次都会检查共享数据结构,以查找某个值。但这是在浪费时间和资源,而且这种繁忙查询的效率非常低。同样,在每次检查之间让线程短暂地进入睡眠,比如睡眠3s,但是因此线程代码就无法最快作出响应。
问题的解决: 条件变量通过允许线程阻塞和等待另一个线程发送信号的方法弥补了互斥锁的不足,条件变量常和互斥锁一起使用。使用时,条件变量被用来阻塞一个线程,当条件不满足时,线程往往解开相应的互斥锁并等待条件发生变化。一旦其它的某个线程改变了条件变量,它将通知相应的条件变量唤醒一个或多个正被此条件变量阻塞的线程。这些线程将重新锁定互斥锁并重新测试条件是否满足。
四、线程管理相关代码
//省略了线程互斥量以及条件变量的初始化
//线程管理:阻塞sec秒读取线程信息
//三个参数分别为:线程信息、线程ID、超时秒数
bool ManagePthread_TimeReadSignal(PTHREAD_BUF *rbuf, PTHREAD_ID thread_num, int sec)
{
bool b_valid = false;
struct timespec to;
int err;
to.tv_sec = time(NULL) + sec;
to.tv_nsec = 0;
//上锁
pthread_mutex_lock(&managePthread.g_pthread_mutex[thread_num]);
//超时sec秒阻塞等待,类似select
err = pthread_cond_timedwait(&managePthread.g_pthread_cond[thread_num], &managePthread.g_pthread_mutex[thread_num], &to);
if(err == ETIMEDOUT)
{
pthread_mutex_unlock(&managePthread.g_pthread_mutex[thread_num]);
return false;
}
//获取线程信息
if(managePthread.g_pthread_info[thread_num] == WRITE_FLAG)
{
managePthread.g_pthread_info[thread_num] = READ_FLAG;
memcpy((PTHREAD_BUF *)rbuf, (PTHREAD_BUF *)&managePthread.g_pthread_buf[thread_num], sizeof(PTHREAD_BUF));
b_valid = true;
}
//解锁
pthread_mutex_unlock(&managePthread.g_pthread_mutex[thread_num]);
return b_valid;
}
//阻塞读取线程信息
bool ManagePthread_ReadSignal(PTHREAD_BUF *rbuf, PTHREAD_ID thread_num, bool wait)
{
bool b_valid = false;
pthread_mutex_lock(&managePthread.g_pthread_mutex[thread_num]);
if(wait == true)
pthread_cond_wait(&managePthread.g_pthread_cond[thread_num], &managePthread.g_pthread_mutex[thread_num]);
if(managePthread.g_pthread_info[thread_num] == WRITE_FLAG)
{
managePthread.g_pthread_info[thread_num] = READ_FLAG;
memcpy((PTHREAD_BUF *)rbuf, (PTHREAD_BUF *)&managePthread.g_pthread_buf[thread_num], sizeof(PTHREAD_BUF));
b_valid = true;
}
pthread_mutex_unlock(&managePthread.g_pthread_mutex[thread_num]);
return b_valid;
}
//激活/发送线程信息
bool ManagePthread_SendSignal(PTHREAD_BUF *sbuf, PTHREAD_ID thread_num)
{
bool b_valid = false;
pthread_mutex_lock(&managePthread.g_pthread_mutex[thread_num]);
managePthread.g_pthread_info[thread_num] = WRITE_FLAG;
if(sbuf)
{
memcpy((PTHREAD_BUF *)&managePthread.g_pthread_buf[thread_num], (PTHREAD_BUF *)sbuf, sizeof(PTHREAD_BUF));
}
pthread_mutex_unlock(&managePthread.g_pthread_mutex[thread_num]);
pthread_cond_signal(&managePthread.g_pthread_cond[thread_num]);
b_valid = true;
return b_valid;
}
//广播
bool ManagePthread_BroadcastSignal(PTHREAD_BUF *sbuf, PTHREAD_ID thread_num)
{
bool b_valid = false;
pthread_mutex_lock(&managePthread.g_pthread_mutex[thread_num]);
managePthread.g_pthread_info[thread_num] = WRITE_FLAG;
memcpy((PTHREAD_BUF *)&managePthread.g_pthread_buf[thread_num], (PTHREAD_BUF *)sbuf, sizeof(PTHREAD_BUF));
pthread_mutex_unlock(&managePthread.g_pthread_mutex[thread_num]);
pthread_cond_broadcast(&managePthread.g_pthread_cond[thread_num]);
b_valid = true;
return b_valid;
}