linux——线程同步及互斥锁

张开发
2026/4/7 9:15:47 15 分钟阅读

分享文章

linux——线程同步及互斥锁
全局变量共享线程竞争#includestdio.h #includepthread.h #includeunistd.h #define MAX 10000 int number; void* funA(void* arg) { for(int i0;iMAX;i) { int ret number; ret; number ret; printf(funA id is %ld,number is %d\n,pthread_self(),number); usleep(10); } } void* funB(void* arg) { for(int i0;iMAX;i) { int ret number; ret; number ret; printf(funB id is %ld,number is %d\n,pthread_self(),number); usleep(10); } } int main() { pthread_t pth1,pth2; pthread_create(pth1,NULL,funA,NULL); pthread_create(pth2,NULL,funB,NULL); pthread_join(pth1,NULL); pthread_join(pth2,NULL); return 0; }定义一个全局变量int number;初始 0创建两个线程funA、funB每个线程都要把 number自增 10000 次理论上最终 number 应该 20000但实际运行永远达不到 20000线程A和B在抢占资源造成了数据混乱1、线程同步的概念线程同步多个线程访问「共享资源 / 全局数据」时按照规定顺序、排队执行防止数据乱改、结果出错。为什么要线程同步全局变量、堆内存、文件描述符都是所有线程共享读写数据不是一步 CPU 指令是「读→改→写」多步操作线程随时被 CPU 切换打断一穿插数据就脏了你刚才那个累加不到 20000 就是典型没有同步 →竞态条件 (数据打架) → 结果错误2、线程同步的思想1. 临界资源思想凡是多个线程都能读 / 都能改的数据叫「临界资源」比如全局变量、静态变量、链表、文件、缓冲区 规矩临界资源不能同时改2. 临界区思想操作临界资源的那一段代码叫「临界区代码」int ret number; ret; number ret;这三行就是临界区 规矩临界区同一时间只允许一个线程进去执行3. 互斥思想最常用互斥你用我就不能用我用你就得等着靠「锁」实现进临界区前加锁出临界区后解锁保证永远单线程操作共享数据4. 同步等待 / 唤醒思想不光要互斥还要控制执行顺序A 没写完B 不能读缓冲区空了生产者要等缓冲区满了消费者要等靠条件变量、信号量实现「等待→唤醒」3、互斥量互斥锁1.互斥锁类型创建一把锁 pthread_mutex_t mutex;2.互斥锁的特点多个线程访问共享数据的时候是串行的3.使用互斥锁缺点效率低4.互斥锁使用的步骤创建互斥锁 pthread_mutex_t mutex;初始化pthread_mutex_init(mutex,NULL); -- mutex 1找到线程共同操作的共享数据加锁操作共享资源之前加锁pthread_mutex_lock(mutex); //阻塞 --mutex 0pthread_mutex_trylock(mutex); // 如果锁上锁直接返回不阻塞XXXXXX共享数据操作 //临界区 越小越好解锁pthread_mutex_unlock(mutex); // -- mutex 1阻塞在锁上的线程会被唤醒销毁pthread_mutex_destroy(mutex)5.互斥锁相关函数初始化互斥锁pthread_mutex_init( pthread_mutex_t* restrict mutex, const pthread_mutexattr_t* restrict attr);销毁互斥锁pthread_mutex_destory(pthread_mutex_t* mutex );加锁pthread_mutex_lock(pthread_mutex* mutex)mutex:没有被锁上当前线程会将这把锁锁上被锁上了当前线程阻塞锁被打开之后线程解除阻塞尝试加锁失败返回不阻塞pthread_mutex_trylock(pthread_mutex_t* mutex);没有锁上当前线程会被这把锁加锁如果锁上了不会阻塞返回返回0加锁 成功。没锁上返回错误号if( pthread_mutex_trylock( mutex)0) { //尝试加锁并且成功了 //访问共享资源 XXXXXXXX } else { //错误处理 //或者等待再次尝试加锁 }解锁pthread_mutex_unlock(pthread_mutex_t* mutex)如果我们想要使用互斥锁同步线程所以线程都需要加锁#includestdio.h #includepthread.h #includeunistd.h #define MAX 10000 int number; //create mutex pthread_mutex_t mutex; void* funA(void* arg) { for(int i0;iMAX;i) { //lock pthread_mutex_lock(mutex); int ret number; ret; number ret; printf(funA id is %ld,number is %d\n,pthread_self(),number); //unlock pthread_mutex_unlock(mutex); usleep(10); } } void* funB(void* arg) { for(int i0;iMAX;i) { //lock pthread_mutex_lock(mutex); int ret number; ret; number ret; printf(funB id is %ld,number is %d\n,pthread_self(),number); //unlock pthread_mutex_unlock(mutex); usleep(10); } } int main() { //init mutex pthread_mutex_init(mutex,NULL); pthread_t pth1,pth2; pthread_create(pth1,NULL,funA,NULL); pthread_create(pth2,NULL,funB,NULL); pthread_join(pth1,NULL); pthread_join(pth2,NULL); pthread_mutex_destroy(mutex); return 0; }AB两个线程执行到20000了但由于锁只保证数据安全同一时间只有一个线程修改number最终一定能执行到20000至于执行顺序那是系统调度管的事不归锁管

更多文章