工作中在进行通信业务开发时,遇到一种超时时间内收到回复做处理的业务场景,使用锁+条件变量实现
1:互斥锁和自旋锁接口梳理
1:条件变量通常配合互斥锁一起使用:
相关定义:
pthread_mutex_t g_mutex;
pthread_cond_t g_cond;
相关初始化:
1:函数初始化/销毁:
pthread_mutex_init(&g_mutex, NULL);
pthread_cond_init(&g_cond, NULL);
pthread_cond_destroy(&g_cond);
pthread_mutex_destroy(&g_mutex);
2:静态初始化: ==》不用关注释放
pthread_cond_t blank_cond = PTHREAD_COND_INITIALIZER;
memcpy(&g_cond, &blank_cond, sizeof(pthread_cond_t));
pthread_mutex_t blank_mutex = PTHREAD_MUTEX_INITIALIZER;
memcpy(&g_mutex, &blank_mutex, sizeof(pthread_mutex_t));
相关使用:
1:互斥锁加锁/解锁相关函数:
pthread_mutex_lock(&g_mutex); //加锁
pthread_mutex_unlock(&g_mutex); //解锁
2:条件变量相关函数:
pthread_cond_broadcast(&g_cond); //唤醒所有加锁线程
pthread_cond_signal(&g_cond); //唤醒其中一个加锁线程
pthread_cond_wait(&g_cond, &g_mutex); //没有唤醒一直等待
pthread_cond_timedwait(&g_cond, &g_mutex, &outtime);
//等待唤醒,如果超过定义的时间,则也可以运行
//如果是超时唤醒,返回值非0
2:自选锁的一些梳理
数据结构:
pthread_spinlock_t spinlock;
相关接口:
int pthread_spin_init(pthread_spinlock_t *, int);
int pthread_spin_destroy(pthread_spinlock_t *);
int pthread_spin_lock(pthread_spinlock_t *);
int pthread_spin_unlock(pthread_spinlock_t *);
int pthread_spin_trylock(pthread_spinlock_t *);
初始化时第二个参数指定:
PTHREAD_PROCESS_SHARED:该自旋锁可以在多个进程中的线程之间共享。
PTHREAD_PROCESS_PRIVATE: 仅初始化本自旋锁的线程所在的进程内的线程才能够使用该自旋锁。
2:相关测试代码:
//对条件变量锁进行测试 超时等待 /********************************************* 多个线程通信,要实现一种唤醒或者超时唤醒的处理, pthread_cond_timedwait 进行测试 实现方案: 申请两个线程,同样的逻辑进行测试 ********************************************/ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <pthread.h> #include <sys/time.h> pthread_mutex_t g_mutex; pthread_cond_t g_cond; //两个线程同样的回调 void* thread_callback(void* arg); int main() { //初始化全局锁和条件变量 pthread_mutex_init(&g_mutex, NULL); pthread_cond_init(&g_cond, NULL); pthread_t t[2]; //创建两个线程执行回调 for(int i=0; i<2; i++) { int ret = pthread_create(&t[i], NULL, thread_callback, (void*)1); if(ret != 0) { printf("pthread_create failed. %d \n", ret); return -1; } } sleep(2); //主线程实现对线程回调函数中的阻塞等待进行唤醒 pthread_mutex_lock(&g_mutex); pthread_cond_signal(&g_cond); //唤醒一个 pthread_mutex_unlock(&g_mutex); //相关等待及销毁处理 for(int i = 0; i<2; i++) { pthread_join(t[i], NULL); } pthread_cond_destroy(&g_cond); pthread_mutex_destroy(&g_mutex); return 0; } void* thread_callback(void* arg) { //这里两个线程都用pthread_cond_timedwait 进行等待唤醒 //两种不同的获取时间的方式 struct timeval now; struct timespec outtime; gettimeofday(&now, NULL); outtime.tv_sec = now.tv_sec + 5; //s outtime.tv_nsec = now.tv_usec * 1000; //微妙转为纳秒 int ret = -1; //锁+条件变量实现线程的阻塞一定时间, 或者被唤醒 pthread_mutex_lock(&g_mutex); //等待一定的时间,进行唤醒 ret = pthread_cond_timedwait(&g_cond, &g_mutex, &outtime); pthread_mutex_unlock(&g_mutex); printf("pthread_cond_timedwait return %d \n", ret); return NULL; }
代码运行结果:
可以看出,超时返回值非0
pthread_cond_timedwait return 0 pthread_cond_timedwait return 110