目录
场景
ServerA 起 N 个线程,每个线程执行相同的逻辑,就是去 DB 取一个待执行的任务来执行,也就是常见的任务队列。具体逻辑是:
- lock tableA
- get 1 new task
- update task status
- unlock tableA
- execute task
- lock tableA
- update task status
- unlock tableA
问题
由于程序存在 bug, 但是线程会异常退出,异常退出时和 DB 之间的连接并没有关闭(潜意识里认为线程退出连接会自动关闭,进而锁会被释放),而异常恰好出现在 lock tableA 和 unlock tableA 之前,这样就会导致表一直被锁。
关于文件描述符
需要明确是,文件描述符是进程级资源(父子进程情况除外),只要进程不退出,即使创建 fd 的线程退出,该 fd 也不会自动关闭。也就是说,一个 fd 是所有线程通用的,ThreadA 创建的 fdA, ThreadB 可以直接引用;同样的,ThreadA 退出时,fdA 也不会被自动关闭,尽管 fdA 是 ThreadA 创建的。
因此,多线程程序对 DB 加锁是非常危险的,如果万不得已加了锁就一定要保证所有导致线程退出的异常逻辑都要关闭连接,以及不要通过线程退出来隐式关闭连接。