发布于2026-07-20 阅读(0)
扫一扫,手机访问
在Linux上搞C++多线程,其实没那么玄乎。从C++11开始,标准库直接提供了头文件,意味着你不需要再折腾那些底层的POSIX线程API了。下面就把常用的几个步骤和模式拆开讲讲,边看代码边理解,上手会快很多。
动手之前,先确认系统里有没有装好GCC编译器和GDB调试器。大多数Linux发行版默认不带开发工具,所以可以跑一下这两条命令:
sudo apt-get update
sudo apt-get install build-essential gdb
装完就算准备好环境了。
来看一个最简单的例子——创建一个线程,让它打个招呼,然后主线程等着它结束。代码非常直观:
#include
#include
void helloFunction() {
std::cout << "Hello from a thread!" << std::endl;
}
int main() {
std::thread t(helloFunction);
t.join();
std::cout << "Hello from the main thread!" << std::endl;
return 0;
}
这里join()的作用就是让主线程停住,等子线程跑完再继续往下走。如果不等,主线程可能直接结束,导致子线程还没来得及输出就被强制终止了。
编译时记得加两个参数:指定C++11标准(或更高),以及链接pthread库。命令长这样:
g++ -std=c++11 -pthread your_program.cpp -o your_program
注意那个-pthread,少了它链接会报错,因为C++的线程库底层还是依赖POSIX线程的。
编译成功后的可执行文件直接跑:
./your_program
输出应该能看到两行“Hello”,顺序不一定,但主线程那行肯定在子线程之后——因为join保证了这一点。
实际场景里,多个线程往往要操作同一个数据,比如打印消息、更新计数器。这时候没有锁就会乱套。C++11提供了std::mutex,用法很简单:
#include
#include
#include
std::mutex mtx;
void printMessage(const std::string& msg) {
mtx.lock();
std::cout << msg << std::endl;
mtx.unlock();
}
int main() {
std::thread t1(printMessage, "Hello from thread 1!");
std::thread t2(printMessage, "Hello from thread 2!");
t1.join();
t2.join();
return 0;
}
每个线程在输出前先抢锁,抢到之后独占输出,保证两条消息不会混在一起。不过手动lock/unlock容易忘,推荐用std::lock_guard自动管理,但这里只是展示最朴素的写法。
条件变量适合一种场景:一个线程要等另一个线程准备好某些条件再开始干活。比如下面这个例子,工作线程一直等着,直到主线程把ready设为true并通知它:
#include
#include
#include
#include
std::mutex mtx;
std::condition_variable cv;
bool ready = false;
void workerThread() {
std::unique_lock lock(mtx);
cv.wait(lock, []{ return ready; });
std::cout << "Worker thread is processing data..." << std::endl;
}
int main() {
std::thread worker(workerThread);
// 主线程准备数据
{
std::lock_guard lock(mtx);
ready = true;
}
cv.notify_one();
worker.join();
return 0;
}
这里的关键是cv.wait会阻塞线程,同时释放锁;等到被通知后,它会重新获取锁并检查条件(lambda表达式)。如果条件不满足,它会继续等待,避免虚假唤醒的问题。
如果只是简单的计数器累加,用锁显得有点重。C++11的std::atomic可以做到无锁的原子操作,性能更好。看一个例子:两个线程各自对同一个原子变量加10万次,最终结果一定是20万:
#include
#include
#include
std::atomic counter(0);
void incrementCounter() {
for (int i = 0; i < 100000; ++i) {
counter++;
}
}
int main() {
std::thread t1(incrementCounter);
std::thread t2(incrementCounter);
t1.join();
t2.join();
std::cout << "Counter value: " << counter << std::endl;
return 0;
}
注意counter++这个操作在原子变量上本身就是线程安全的,不需要额外加锁。当然,原子操作只适合简单的整型或指针,复杂的共享数据结构还是得靠互斥锁。
这几个例子基本覆盖了C++多线程编程的常见场景:创建线程、同步、条件等待、原子操作。掌握了这些,后面再去看线程池、任务队列那些进阶内容,思路会清晰很多。实际开发中,记得多考虑异常安全和死锁问题,多写测试,慢慢就能写出健壮的多线程程序了。
上一篇:lsnrctl如何自定义脚本集成
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
正版软件
正版软件
正版软件
正版软件
正版软件
1
2
3
7
8