C++中main函数读取线程修改的全局变量时互斥锁的使用及资源疑问
关于主线程使用互斥锁同步全局变量的问题
当然可以在main()函数里使用互斥锁来实现你的同步逻辑,而且主线程本身并不会因为这个操作占用过多资源影响其他线程的正常运行——只要你正确使用同步机制就行。我来拆解一下关键点:
1. 互斥锁的核心作用:保护共享资源的原子访问
不管是主线程(main函数)还是你创建的UDP监听线程,只要涉及到对全局变量的读写操作,都必须通过互斥锁来包裹。这是避免竞态条件的标准做法:
- 线程修改全局变量前加锁,修改完成后解锁
- main函数读取全局变量前加锁,读取完成后解锁
这样就能保证全局变量的读写操作是原子性的,不会出现半写半读的错误状态。
2. 主线程的资源占用问题:和互斥锁无关,取决于循环逻辑
main函数本质上就是一个普通的主线程,它在循环里读取全局变量的操作本身开销极小。真正可能导致CPU占用过高的情况是忙等循环(比如没有任何延迟的空转),但这和使用互斥锁没有关系——你只需要在循环里加一个短时间的sleep()或者usleep(),就能大幅降低主线程的CPU使用率,同时完全不影响同步逻辑。
示例代码参考
这里给你一个简化的实现框架,展示如何在主线程和子线程中正确使用互斥锁:
#include <pthread.h> #include <unistd.h> #include <iostream> // 全局共享变量 int port_data[3] = {0, 0, 0}; // 全局互斥锁,初始化要正确 pthread_mutex_t data_mutex = PTHREAD_MUTEX_INITIALIZER; // UDP监听线程函数 void* udp_listen_thread(void* arg) { int target_port = *(int*)arg; // 省略UDP套接字创建、绑定、接收数据的代码... while (true) { // 假设从UDP数据包中解析出要更新的值 int received_value = /* 解析逻辑 */; int data_index = target_port - 1000; // 假设端口1000对应索引0 // 修改全局变量前加锁 pthread_mutex_lock(&data_mutex); port_data[data_index] = received_value; pthread_mutex_unlock(&data_mutex); // 模拟处理间隔,避免过度占用CPU usleep(50000); } return nullptr; } int main() { pthread_t threads[3]; int ports[3] = {1000, 1001, 1002}; // 创建3个UDP监听线程 for (int i = 0; i < 3; ++i) { if (pthread_create(&threads[i], nullptr, udp_listen_thread, &ports[i]) != 0) { std::cerr << "Failed to create thread " << i << std::endl; return 1; } } // 主线程循环读取全局变量 while (true) { // 读取前加锁,保证数据一致性 pthread_mutex_lock(&data_mutex); std::cout << "Current port values: " << port_data[0] << ", " << port_data[1] << ", " << port_data[2] << std::endl; pthread_mutex_unlock(&data_mutex); // 加延迟,避免忙等占用过多CPU sleep(1); } // 实际项目中记得回收线程、销毁互斥锁 for (int i = 0; i < 3; ++i) { pthread_join(threads[i], nullptr); } pthread_mutex_destroy(&data_mutex); return 0; }
额外注意事项
- 避免死锁:不要在持有互斥锁的情况下调用可能长期阻塞的函数(比如UDP的
recvfrom如果设置为阻塞模式,就不要在加锁后调用),否则会导致其他线程无法获取锁,一直阻塞。正确的做法是先接收数据,再加锁修改全局变量。 - 锁的粒度:尽量缩小锁的范围,只在读写共享变量的代码段加锁,不要把整个线程的逻辑都包裹在锁里,这样能减少锁竞争的概率,提升性能。
- 互斥锁初始化:确保互斥锁被正确初始化(比如用
PTHREAD_MUTEX_INITIALIZER静态初始化,或者pthread_mutex_init动态初始化),否则会导致未定义行为。
内容的提问来源于stack exchange,提问作者Ali Nouri
相关产品推荐
相关产品推荐

