C语言使用ncurses库时pthread子线程打印输出异常如何解决
问题原因分析
- ncurses 函数库本身不是线程安全的,默认没有对内部的屏幕缓冲区、光标位置等共享资源加互斥锁,你在子线程直接调用
mvprintw、refresh这类ncurses接口,如果主线程同时也在调用其他ncurses绘制接口,就会导致缓冲区数据错乱,出现乱码。 - 你的倒计时输出没有擦除旧内容,比如倒计时从10变成9的时候,上一次输出的10的第二位0还留在屏幕上,就会显示为异常内容。
- 子线程的死循环没有加延时,会疯狂抢占CPU资源,高频调用刷新接口,进一步加剧缓冲区冲突的概率。
修复方案
- 首先加互斥锁保护所有ncurses调用,所有线程(包括主线程和定时器子线程)调用ncurses的绘制、刷新接口前都要先获取同一个互斥锁,调用结束后立即释放。
首先定义全局互斥锁:
pthread_mutex_t ncurses_lock = PTHREAD_MUTEX_INITIALIZER;
修改后的定时器线程代码如下:
void *timer(void *arg){ time_t current = time(0); time_t stop = current + 30; while (1){ current = time(0); if (current <= stop){ int now = stop - current; // 调用ncurses接口前加锁 pthread_mutex_lock(&ncurses_lock); // 用固定宽度输出自动覆盖旧的多余字符 mvprintw(0, 0, "%2d", now); refresh(); pthread_mutex_unlock(&ncurses_lock); } else { // 倒计时结束直接退出线程,避免无意义循环 break; } // 加1秒延时,不需要高频刷新 sleep(1); } return NULL; }
- 主线程所有的
mvprintw、printw、refresh、getch等ncurses接口调用,同样需要加同一把互斥锁保护。 - 编译时要确保正确链接依赖库,编译命令示例:
gcc your_code.c -o runnable -lncurses -lpthread
额外注意点
- 如果没有其他子线程任务需求,也可以不用多线程实现倒计时,直接在主线程的事件循环里用非阻塞
getch配合时间差计算倒计时,完全规避线程安全问题。 - 程序退出前要调用
pthread_join回收定时器子线程资源,并且销毁互斥锁。
内容的提问来源于stack exchange,提问作者Jakub Kolesár
相关产品推荐
相关产品推荐

