🎬 HoRain 云小助手:个人主页
⛺️生活的理想,就是为了理想的生活!
⛳️ 推荐
前些天发现了一个超棒的服务器购买网站,性价比超高,大内存超划算!忍不住分享一下给大家。点击跳转到网站。
目录
三、条件变量(Condition Variable):线程间的信号灯
在多线程编程中,线程管理、数据同步是开发者必须掌握的核心技能。本文将通过浅显易懂的方式,结合代码示例讲解Linux线程ID、**互斥锁(Mutex)和条件变量(Condition Variable)**的使用。
一、线程ID:线程的唯一身份证
每个线程在创建时都会被分配一个唯一的线程ID(类型为pthread_t
),类似于进程的PID。通过线程ID,我们可以对特定线程进行操作(如取消线程)。
关键函数:
- 获取当前线程ID:
pthread_self()
- 比较线程ID:
pthread_equal(tid1, tid2)
#include <pthread.h>
#include <stdio.h>
void* thread_func(void* arg) {
pthread_t tid = pthread_self();
printf("Thread ID: %lu\n", (unsigned long)tid);
return NULL;
}
int main() {
pthread_t tid;
pthread_create(&tid, NULL, thread_func, NULL);
printf("Main thread ID: %lu\n", (unsigned long)pthread_self());
pthread_join(tid, NULL);
return 0;
}
注意:
pthread_t
的具体实现可能不同(可能为结构体),因此必须使用pthread_equal
比较线程ID,不能直接用==
。
二、互斥锁(Mutex):解决数据竞争
当多个线程同时访问共享资源时,可能导致数据竞争(Data Race)。互斥锁通过“加锁”机制确保同一时间只有一个线程访问临界区。
核心操作:
- 初始化:
pthread_mutex_init()
- 加锁:
pthread_mutex_lock()
- 解锁:
pthread_mutex_unlock()
- 销毁:
pthread_mutex_destroy()
示例:线程安全的计数器
#include <pthread.h>
#include <stdio.h>
int counter = 0;
pthread_mutex_t mutex;
void* increment(void* arg) {
for (int i = 0; i < 100000; ++i) {
pthread_mutex_lock(&mutex);
counter++; // 临界区
pthread_mutex_unlock(&mutex);
}
return NULL;
}
int main() {
pthread_mutex_init(&mutex, NULL);
pthread_t t1, t2;
pthread_create(&t1, NULL, increment, NULL);
pthread_create(&t2, NULL, increment, NULL);
pthread_join(t1, NULL);
pthread_join(t2, NULL);
printf("Final counter: %d\n", counter); // 正确输出200000
pthread_mutex_destroy(&mutex);
return 0;
}
若不加锁:最终结果可能小于200000,因为两个线程可能同时读取旧值并写入。
三、条件变量(Condition Variable):线程间的信号灯
条件变量用于线程间的协同工作,典型场景是“生产者-消费者”模型。它需要与互斥锁配合使用。
核心操作:
- 等待条件:
pthread_cond_wait(cond, mutex)
- 通知条件:
pthread_cond_signal(cond)
(唤醒一个线程)或pthread_cond_broadcast(cond)
(唤醒所有线程)
示例:生产者-消费者模型
#include <pthread.h>
#include <stdio.h>
int data = 0;
pthread_mutex_t mutex;
pthread_cond_t cond;
void* producer(void* arg) {
pthread_mutex_lock(&mutex);
data = 42; // 生产数据
printf("Produced data: %d\n", data);
pthread_cond_signal(&cond); // 通知消费者
pthread_mutex_unlock(&mutex);
return NULL;
}
void* consumer(void* arg) {
pthread_mutex_lock(&mutex);
while (data == 0) { // 必须用循环避免虚假唤醒
pthread_cond_wait(&cond, &mutex);
}
printf("Consumed data: %d\n", data);
pthread_mutex_unlock(&mutex);
return NULL;
}
int main() {
pthread_mutex_init(&mutex, NULL);
pthread_cond_init(&cond, NULL);
pthread_t t_producer, t_consumer;
pthread_create(&t_consumer, NULL, consumer, NULL);
pthread_create(&t_producer, NULL, producer, NULL);
pthread_join(t_producer, NULL);
pthread_join(t_consumer, NULL);
pthread_mutex_destroy(&mutex);
pthread_cond_destroy(&cond);
return 0;
}
四、总结
- 线程ID是线程的唯一标识,不可直接比较。
- 互斥锁解决数据竞争问题,确保临界区原子性。
- 条件变量用于线程间协同,需配合互斥锁使用。
注意事项:
- 加锁后必须及时解锁,避免死锁。
- 条件变量等待必须使用
while
循环检查条件(防止虚假唤醒)。
掌握这些基础同步机制后,可以更安全地开发高效的多线程程序。建议动手运行示例代码,观察不同场景的输出结果!
❤️❤️❤️本人水平有限,如有纰漏,欢迎各位大佬评论批评指正!😄😄😄
💘💘💘如果觉得这篇文对你有帮助的话,也请给个点赞、收藏下吧,非常感谢!👍 👍 👍
🔥🔥🔥Stay Hungry Stay Foolish 道阻且长,行则将至,让我们一起加油吧!🌙🌙🌙