线程间同步的几种方式:让你的程序不再“抢资源”

{"title":"线程同步的几种方式:让你的程序不再“抢资源”","content":"

线程间同步的几种方式

\n

写过多线程程序的人,多少都遇到过这种问题:两个线程同时修改同一个变量,结果数据乱了。就像你和室友同时往冰箱里放牛奶,谁也不知道对方已经买了,最后塞了五盒,过期三盒。这就是典型的“资源竞争”。解决这类问题,就得靠线程间同步。

\n\n

互斥锁(Mutex)

\n

最常用的同步手段就是互斥锁。它像一把钥匙,只有拿到钥匙的线程才能进入临界区操作共享资源。其他线程只能等着,直到钥匙被归还。

\n

比如你在写一个日志系统,多个线程都要往同一个文件写记录。如果不加锁,内容可能交错在一起,变成“用户A登用户B录成功失败”。加上互斥锁后,每次只有一个线程能写,顺序就保住了。

\n
#include <pthread.h>\n\npthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;\nint shared_data = 0;\n\nvoid* thread_func(void* arg) {\n    pthread_mutex_lock(&lock);\n    shared_data++;\n    pthread_mutex_unlock(&lock);\n    return NULL;\n}
\n\n

信号量(Semaphore)

\n

互斥锁一次只允许一个线程进入,而信号量可以控制最多几个线程同时访问。它像是停车场的空位计数器,进来一辆车,空位减一;出去一辆,加一。当空位为零时,新来的车就得等。

\n

比如你有个数据库连接池,最多支持10个并发连接。用信号量就能轻松控制,避免资源耗尽。

\n
#include <semaphore.h>\n\nsem_t sem;\n\nvoid* worker(void* arg) {\n    sem_wait(&sem);  // 获取许可\n    // 执行数据库操作\n    sem_post(&sem);  // 释放许可\n    return NULL;\n}
\n\n

条件变量(Condition Variable)

\n

有时候线程不能光靠“等”,还得知道“等什么”。条件变量就是用来配合互斥锁,让线程在某个条件不满足时挂起,直到别的线程通知它。

\n

好比你等快递,不会一直打电话问,而是让快递员到了再通知你。在生产者-消费者模型里特别常见:消费者发现队列空了,就wait;生产者放进新任务后,调用signal唤醒消费者。

\n
pthread_mutex_t mutex;\npthread_cond_t cond;\nint ready = 0;\n\nvoid* consumer(void* arg) {\n    pthread_mutex_lock(&mutex);\n    while (!ready) {\n        pthread_cond_wait(&cond, &mutex);\n    }\n    // 处理任务\n    pthread_mutex_unlock(&mutex);\n    return NULL;\n}\n\nvoid* producer(void* arg) {\n    pthread_mutex_lock(&mutex);\n    ready = 1;\n    pthread_cond_signal(&cond);\n    pthread_mutex_unlock(&mutex);\n    return NULL;\n}
\n\n

读写锁(Read-Write Lock)

\n

有些场景下,读操作多、写操作少。如果每次读都用互斥锁,效率太低。读写锁允许多个线程同时读,但写的时候必须独占。

\n

比如一个配置缓存,大多数时候是读取,偶尔才更新。用读写锁,读的时候大家都能进,写的时候全员暂停,既安全又高效。

\n
pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;\n\nvoid* reader(void* arg) {\n    pthread_rwlock_rdlock(&rwlock);\n    // 读取共享数据\n    pthread_rwlock_unlock(&rwlock);\n    return NULL;\n}\n\nvoid* writer(void* arg) {\n    pthread_rwlock_wrlock(&rwlock);\n    // 修改共享数据\n    pthread_rwlock_unlock(&rwlock);\n    return NULL;\n}
\n\n

原子操作

\n

对于简单的变量操作,比如自增、赋值,可以直接用原子操作。它由硬件保证不会被打断,不需要加锁,性能更高。

\n

就像抢红包,每人点一下金额减一次。用原子减法,就不会出现两个人同时看到同一笔余额的情况。

\n
#include <atomic>\n\nstd::atomic<int> counter(0);\n\nvoid increment() {\n    counter.fetch_add(1);\n}
\n\n

每种同步方式都有适用的场景。选对工具,程序才能既安全又流畅。别让线程之间的“争抢”拖慢了你的应用。”,"seo_title":"线程间同步的几种方式详解 - 信息生活家","seo_description":"了解互斥锁、信号量、条件变量、读写锁和原子操作等线程间同步方式,解决多线程编程中的资源竞争问题。","keywords":"线程间同步,互斥锁,信号量,条件变量,读写锁,原子操作,多线程编程,线程安全"}