Linux线程死锁详解
有关 4 种线程同步机制的详细讲解,您可以点击《多线程编程(C语言+Linux)》做系统地学习。
线程死锁指的是线程需要使用的公共资源一直被其它线程占用,导致该线程一直处于 阻塞 状态,无法继续执行。举个例子,用互斥锁实现线程同步的过程中,初学者经常忘记为 加锁 的线程及时 解锁 ,这种情况下就会发生死锁(实例一):
#include stdio.h #include pthread.h //创建并初始化互斥锁 pthread_mutex_t myMutex = PTHREAD_MUTEX_INITIALIZER; void *thread_func(void *arg) { int islock; //为线程加锁 islock = pthread_mutex_lock( myMutex); if (islock == 0) { printf( 线程 %u 已加锁/n , pthread_self()); return 0; int main() { int flag; int i; //创建 4 个线程 pthread_t tids[4]; for (i = 0; i i++) flag = pthread_create( tids[i], NULL, thread_func, NULL); if (flag == 0) { printf( 线程 %u 创建完成/n ,tids[i]); for(i = 0; i i++){ pthread_join(tids[i], NULL); printf( 线程 %u 执行完成/n ,tids[i]); return 0; }
假设程序编写在 thread.c 文件中,执行过程如下:
[root@localhost ~]# gcc thread.c -o thread.exe -lpthread
[root@localhost ~]# ./thread.exe
线程 3135751936 创建完成
线程 3125262080 创建完成
线程 3114772224 创建完成
线程 3135751936 已加锁
线程 3104282368 创建完成
线程 3135751936 执行完成
其它 3 个线程发生了死锁
程序中共创建了 4 个线程,它们都执行 thread_func() 函数,该函数内完成了对互斥锁的 加锁 操作,但没有调用 pthread_mutex_unlock() 函数对互斥锁 解锁 。通过程序的执行结果可以看到,4 个线程中仅有 1 个线程成功执行结束,其它 3 个线程一直处于等待互斥锁 解锁 的阻塞状态,发生了死锁。
再举一个例子(实例二):
#include stdio.h #include pthread.h #include unistd.h pthread_mutex_t mutex; pthread_mutex_t mutex2; void *func1(void *args) pthread_mutex_lock( mutex); printf( t1 成功申请 mytex 锁/n sleep(2); pthread_mutex_lock( mutex2); printf( t1 成功申请 mytex2 锁/n printf( %u is running/n ,pthread_self()); pthread_mutex_unlock( mutex); printf( ------%u done/n ,pthread_self()); void *func2(void *args) pthread_mutex_lock( mutex2); printf( t2 成功申请 mytex2 锁/n sleep(2); pthread_mutex_lock( mutex); printf( t2 成功申请 mytex 锁/n printf( %u is running/n ,pthread_self()); pthread_mutex_unlock( mutex); printf( ------%u done/n ,pthread_self()); int main() int ret; pthread_t t1; pthread_t t2; pthread_mutex_init( mutex,NULL); pthread_mutex_init( mutex2,NULL); ret = pthread_create( t1, NULL, func1, NULL); if(ret != 0){ printf( create t1 fail/n ret = pthread_create( t2, NULL, func2, NULL); if(ret != 0){ printf( create t2 fail/n pthread_join(t1,NULL); pthread_join(t2,NULL); pthread_mutex_destroy( mutex); pthread_mutex_destroy( mutex2); return 0; }
假设程序编写在 thread.c 文件中,执行过程如下:
[root@localhost ~]# gcc thread.c -o thread.exe -lpthread
[root@localhost ~]# ./thread.exe
t1 成功申请 mytex 锁
t2 成功申请 mytex2 锁
t1 和 t2 都发生了死锁
程序中创建了 mutex 和 mutex2 两个互斥锁,线程 t1 和 t2 同时执行。从执行结果可以看到,t1 成功申请了 mutex 锁,t2 成功申请了 mutex2 锁,t1 一直等待 t2 释放 mutex2 锁,而 t2 一直等待 t1 释放 mutex 锁,两个线程都因等待对方释放资源产生了死锁。
总的来说,当进程空间中的某公共资源不允许多个线程同时访问时,某线程访问公共资源后不及时释放资源,就很可能产生线程死锁。
避免线程死锁的几点建议1) 使用互斥锁、信号量、条件变量和读写锁实现线程同步时,要注意以下几点:
注意,函数中可以设置多种结束执行的路径,但无论线程选择哪个路径结束执行,都要保证能够将占用的资源释放掉。
2) POSIX 标准中,很多阻塞线程执行的函数都提供有 tryxxx() 和 timexxx() 两个版本,例如 pthread_mutex_lock() 和 pthread_mutex_trylock()、sem_wait() 和 sem_trywait()、pthread_cond_wait() 和 pthread_cond_timedwait() 等,它们可以完成同样的功能,但 tryxxx() 版本的函数不会阻塞线程,timexxx() 版本的函数不会一直阻塞线程。
实际开发中,建议您优先选择 tryxxx() 或者 timexxx() 版本的函数,可以大大降低线程产生死锁的概率。
3) 多线程程序中,多个线程请求资源的顺序最好保持一致。实例二中,线程 t1 先请求 mutex 锁然后再请求 mutex2 锁,而 t2 则是先请求 mutex2 锁然后再请求 mutex 锁,这就是典型的因 请求资源顺序不一致 导致发生了线程死锁的情况。
21433.html
C语言GCClinux多线程相关文章
- 【深入探索:Linux动态链接库】(动态链接库linux)
- Linux系统下防火墙配置指南(linux下防火墙配置)
- Linux格式化XFS分区:开启新的存储生活(linux格式化xfs)
- Linux之驱动精灵:驱动无忧。(linux驱动精灵)
- Linux绿色文件:健康使用之要义(linux绿色是什么文件)
- 如何在Linux系统中配置域名(linux怎么配域名)
- Linux网络关闭指南:一步一步快速实现(linux关闭网络)
- Linux 下 DNS 解析域名实践(linux解析域名)
- Linux线程共享:解决编程挑战(linux线程共享)
- 深入了解Linux中的阻塞线程(linux阻塞线程)
- 开启Linux之路:探索伪线程(linux伪线程)
- 如何关闭Linux系统中的调试串口?(linux关闭调试串口)
- 如何在Linux系统下轻松重启FTP服务(linux重启ftp服务)
- 开启Linux之旅:深度体验Linux精彩世界(linux系统总结)
- Linux环境下线程栈大小优化研究(linux线程栈大小)
- 解析Linux运行缓慢问题,优化电脑性能(linux运行慢)
- 掌握Linux运行时间的技巧与方法(linux运行时间)
- 深入了解Linux线程:如何使用PS进行进程管理(linux线程ps)
- Linux防火墙iptables学习笔记(五)linux+iptables构筑防火墙实例
- Linux串口驱动编写详解(linux串口驱动编写)
- Linux目录权限详解:让你彻底了解目录权限设置!(linux下目录权限)
- 器学会用Linux vi编辑器,拥抱编程之美(linux vi 编辑)