成对Barrier线程同步:同色线程配对返回匹配ID的实现问题
问题分析
现有代码的核心问题出在共享状态的重置时机、信号量的复用冲突两个方面,具体如下:
- 全局信号量
a1/a2/barr没有按颜色隔离,同时多组同色线程进入时会互相抢占信号量,导致配对id错位 count[0]的计数逻辑没有正确闭环:第一对配对完成后的状态没有安全重置,第三、第四个线程进入时计数逻辑会出现越界或者配对混乱- 非临界区的
map读写没有保护:else分支中修改map[0][1]和重置count[0]时没有加锁,可能和其他线程的写入操作冲突
修正实现思路
每个颜色独立维护一套状态变量,避免不同颜色、不同配对批次的线程互相干扰,单种颜色的状态变量包含:
- 互斥信号量
lock:保护计数和配对id数组的读写 - 同步信号量
rendezvous:实现两个线程的会合等待 - 计数变量
count:记录当前进入的同色线程数量 - 配对存储数组
pair_ids:暂存两个配对线程的id
初始化注意事项
使用前需要对每个颜色的状态变量进行初始化,示例初始化代码如下:
// 假设共3种颜色,可按实际需求调整数量 typedef struct { sem_t lock; sem_t rendezvous; int count; int pair_ids[2]; } ColourState; ColourState states[3] = {0}; // 初始化调用逻辑 for (int i = 0; i < 3; i++) { sem_init(&states[i].lock, 0, 1); sem_init(&states[i].rendezvous, 0, 0); states[i].count = 0; }
修正后函数实现
int pack_thread(int colour, int id) { // 颜色映射为数组下标,可按实际规则调整 int idx = colour - 1; ColourState *s = &states[idx]; sem_wait(&s->lock); int pos = s->count; s->pair_ids[pos] = id; s->count++; if (s->count == 1) { // 第一个到达的线程,释放锁后等待第二个线程会合 sem_post(&s->lock); sem_wait(&s->rendezvous); return s->pair_ids[1 - pos]; } else { // 第二个到达的线程,唤醒等待的第一个线程,重置状态后返回 int ret = s->pair_ids[1 - pos]; s->count = 0; sem_post(&s->rendezvous); sem_post(&s->lock); return ret; } }
逻辑说明
- 互斥信号量
lock保证同一时间只有一个线程修改对应颜色的计数和id存储,避免竞态 - 第一个进入的线程记录id后释放锁,阻塞等待会合信号
- 第二个进入的线程记录id后,直接唤醒等待的第一个线程,同时重置计数,准备下一批同色线程配对
- 两个线程分别返回对方存储的id,不存在交叉读写的问题,多对线程顺序进入也不会出现id错位
内容的提问来源于stack exchange,提问作者user624
相关产品推荐
相关产品推荐

