字节对齐导致pthread_cond_timedwait 占用高CPU问题

博客讲述了在程序中添加内存管理模块导致其他线程CPU占用升高的问题,问题源于pthread_cond_timedwait的超时时间计算错误,以及内存对齐设置的影响。通过调整内存对齐方式,成功降低了CPU占用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Mark下调试中出现的诡异现象,在程序中添加一个内存管理模块后,导致了其他线程占用高cpu,

该线程的线程栈如下(该线程主要功能就是处理模块间的消息):

#0  0x00007f81b7d48da2 in pthread_cond_timedwait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
#1  0x0000000000416a80 in MsgQueue::Dequeue (this=0x13af1961, item=...) at ../public/xx/xxx.h:109
#2  0x0000000000416198 in module_message (arg=0xb0deb0 <ModuleMgr+4848>) at ../public/xx/xxx.cpp:17
#3  0x00007f81b7d44e65 in start_thread () from /lib64/libpthread.so.0
#4  0x00007f81b5e6288d in clone () from /lib64/libc.so.6

查阅资料发现有网友(https://bbs.youkuaiyun.com/topics/390787479)也出现过类似问题,其调用pthread_cond_timedwait代码如下,问题是pthread_cond_timedwait的最后参数outtime赋值错误导致,错误语句:

outtime.tv_nsec = now.tv_usec,两边的单位不一样,一个是纳秒,一个是微秒。这样赋值会使得pthread_cond_timewait的超时时间比当前时间还小。

        gettimeofday(&now, NULL);
        now.tv_usec += ms * 1000;
        if(now.tv_usec >= 1000000)
        {
            now.tv_sec += now.tv_usec / 1000000;
            now.tv_usec %= 1000000;
        }
        outtime.tv_nsec = now.tv_usec;
        outtime.tv_sec = now.tv_sec;
        int ret = pthread_cond_timedwait(&cond, &mutex, &outtime);

而我这里也这么赋值,但是tv_usec*1000后来赋值的,还是出现高cpu,后面各种调试还是高

t.tv_sec = now.tv_sec+1;
t.tv_nsec = now.tv_usec*1000;

小伙伴调试这个部分代码时就是各种coredump,到我这里就是高cpu(说明一下:小伙伴和我使用代码的平台不一样,当然编译器和运行平台不一样),修改了内存管理模块头文件的对齐方式(原来是1字节对齐,修改为4字节对齐)后,不挂了,我这尝试修改对齐cpu也神奇的降下来了

神奇的字节对齐

后来查阅资料,人家说互斥锁一字节对齐导致的,不知道为什么

### 正确使用 `pthread_cond_timedwait` 实现等待直到条件满足 为了确保线程能够安全地等待特定条件的发生,可以采用如下方法来正确使用 `pthread_cond_timedwait` 函数。此函数允许指定一个超时时间,在这段时间内如果没有达到预期条件,则会返回给调用者。 #### 初始化互斥锁和条件变量 在开始之前,需要初始化互斥量 (`mutex`) 和条件变量 (`cond_var`). 这两个对象用于同步访问共享资源以及通知其他线程当某些事件发生时唤醒它们: ```c++ #include <pthread.h> #include <time.h> // 定义全局或类成员变量 pthread_mutex_t mutex; pthread_cond_t cond_var; void init_sync_objects() { pthread_mutex_init(&mutex, NULL); pthread_cond_init(&cond_var, NULL); } ``` #### 设置绝对超时时间 对于 `pthread_cond_timedwait`, 需要提供一个表示绝对时刻的时间结构体作为参数。通常情况下,可以通过获取当前时间和增加一定的延迟来计算这个未来的时间点: ```c++ struct timespec get_timeout_time(int seconds_into_future) { struct timespec ts; clock_gettime(CLOCK_REALTIME, &ts); // 获取实时钟表时间 // 增加秒数到纳秒级别上 ts.tv_sec += seconds_into_future; return ts; } ``` #### 使用 `pthread_cond_timedwait` 现在可以在适当的位置插入下面这段代码片段,它展示了如何让线程进入休眠状态并等待另一个线程通过信号触发其继续执行: ```c++ bool wait_until_condition_is_met(bool* condition_flag_ptr, int timeout_seconds) { bool result = false; pthread_mutex_lock(&mutex); while (!(*condition_flag_ptr)) { struct timespec abs_timeout = get_timeout_time(timeout_seconds); int ret_val = pthread_cond_timedwait( &cond_var, &mutex, &abs_timeout ); if (ret_val == ETIMEDOUT) break; // 超时则退出循环 // 如果不是因为超时而醒来,则重新检查条件标志位 } if (*condition_flag_ptr) { *condition_flag_ptr = false; // 清除条件标记 result = true; } pthread_mutex_unlock(&mutex); return result; } ``` 上述代码实现了以下功能: - 锁定互斥量以保护对共享数据的操作。 - 当前条件下不成立时反复调用 `pthread_cond_timedwait`. - 计算出期望的绝对结束时间,并将其传递给 `pthread_cond_timedwait`. - 若因超时原因被唤醒,则终止等待过程;否则再次验证条件是否已达成. - 解锁互斥量以便其他线程可以获得该锁. 需要注意的是,这里假设有一个外部机制负责设置 `*condition_flag_ptr` 的值为真,从而告知等待中的线程条件已经满足[^2].
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值