几周前我在类里面做了一个练习,我的解决方案很好,但我观察了一段时间后发现了一些奇怪的行为。 练习是用两个 posix 线程生成死锁,然后解决它。 (我抽象了解决方案,因此没有不必要的代码。
场景如下:
- 我有两个共享两个虚构资源的线程
- 两个线程按顺序开始,然后尝试占用两个资源(也按顺序)
- 两个线程占用的时间跨度不同
- 当一个线程同时拥有这两种资源时,他会工作 5 秒,然后释放资源并休息,当休息结束时,他会再次开始尝试占用这两种资源
- 每 8 秒一个函数检查两个线程是否都处于等待状态(两个线程都有一个资源并且正在等待第二个)
- 当死锁发生时,工作更多的线程被取消然后重新启动
问题来了,取决于机器和编译器标志,输出表示例如线程 A 被取消,但随后线程 B 启动。我在具有不同编译器和不同安装的不同计算机上进行了尝试。
奇怪的是我用 gcc -Wall -Werror -ansi -pedantic -D_POSIX_C_SOURCE=200809L -pthread -lrt
编译,第二个死锁出现问题,但是当我删除 -Wall 和 -Werror 时问题3.死锁0o自带
我上传了源here .编译标志在源代码中,我尝试了 gcc 和 clang。
我还尝试了 Ubuntu 13.04 和 Arch。
Here是输出,我用“-->”标记了这些行
我是不是忘记了什么所以出现了这个效果?我认为某些库中没有错误。
最佳答案
问题是您将局部变量的地址传递给线程。并且当线程启动时这个局部变量可能不再存在,并且您正在取消引用用来保存局部变量但现在保存其他东西的地址位置。
因为它在程序的堆栈空间中,所以不会出现段错误。
这里重点介绍了代码的问题区域及其产生原因:
void resolve_deadlock()
{
void *pthread_exit_state;
int id_a = THREAD_A;
int id_b = THREAD_B;
<some code to detect deadlocks and kill a thread>
/* restart the killed thread */
if (pthread_create(&threads[THREAD_B], NULL, &thread_function, (void *) &id_b) != 0) {
perror("Create THREAD_B\n");
exit(EXIT_FAILURE);
}
}
所以程序运行并且:
- 调用resolve_deadlock
- 线程 X 被杀死
- 调用pthread_create创建线程
- resolve_deadlock 函数结束
- 堆栈在下一个函数调用时被覆盖
- 操作系统将我们换出并运行另一个线程
- 线程 X 运行并取消引用我们不再存在的本地变量 -> 未定义的行为。
关于c - 解决死锁时的奇怪行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18039310/