pthread_join 死锁的简单示例
Simple example for pthread_join deadlock
我正在寻找一个非常简单的示例来演示使用 pthread_join
的死锁;然而,这并非微不足道。
我是从这个开始的:
void* joinit(void* tid)
{
pthread_t* tid_c = (pthread_t*)tid;
int retval = pthread_join(*tid_c, NULL);
printf("In joinit: tid = %d, retval = %d \n", *tid_c, retval);
return NULL;
}
int main()
{
pthread_t thread1;
pthread_t thread2;
pthread_create(&thread1, NULL, joinit, &thread2);
pthread_create(&thread2, NULL, joinit, &thread1);
pthread_join(thread2, NULL);
return 0;
}
但是,它说 'EINVAL'(无效参数),因为在调用 thread1
的 pthread_create
时尚未指定 thread2
。
有什么想法吗?
如果您只是想证明 pthread_join
会导致死锁,您可以执行类似于以下代码的操作:
#include <stdio.h>
#include <pthread.h>
void* joinit(void* tid)
{
printf("In %#x, waiting on %#x\n", pthread_self(), (*((pthread_t*)tid)));
pthread_join((*((pthread_t*)tid)), NULL);
printf("Leaving %#x\n", pthread_self());
return NULL;
}
int main(void)
{
pthread_t thread1 = pthread_self();
pthread_t thread2;
pthread_create(&thread2, NULL, joinit, &thread1);
joinit(&thread2);
return 0;
}
这将导致主线程在派生线程上等待,而派生线程在主线程上等待(导致死锁),而不需要额外的锁定原语来扰乱您要演示的内容。
并更直接地回答您的一些问题:
it says 'EINVAL' (invalid argument) because thread2
is not yet specified when pthread_create
for thread1
is called.
...以及您的评论之一...
I tried this and it worked, but the problem is, it only works SOMETIMES because sometimes I get EINVAL again.
在您的代码中,您连续调用 pthread_create
以生成 2 个线程:
pthread_create(&thread1, NULL, joinit, &thread2);
pthread_create(&thread2, NULL, joinit, &thread1);
在您的 joinit
代码中,您获取传入的线程句柄以加入:
pthread_t* tid_c = (pthread_t*)tid;
int retval = pthread_join(*tid_c, NULL);
这个 有时 起作用的原因和你会得到 EINVAL
的其他原因与 time slices allocated to each thread's context and sequencing 有关。当第一个 pthread_create
被调用时,您将在 returns 之后有一个 thread1
的有效句柄,但 thread2
的句柄还无效,至少在第二个 pthread_create
被调用。
为此,当一个线程被创建时,线程的行为"alive"(即线程函数实际上运行)可能需要一些额外的时间,即使返回的线程句柄是有效的.在这些情况下,一个线程执行的代码可能比 "expected" 多。在你的代码中,两个 pthread_create
函数 可能 恰好在分配给主线程的时间片中被调用, 可以 给每个在命中 pthread_join
允许 tid_c
指向有效句柄的语句之前生成足够多的线程 "time";在 EINVAL
的情况下,调用 pthread_create(&thread1, NULL, joinit, &thread2)
并且生成的线程在 pthread_create(&thread2, NULL, joinit, &thread1)
之前命中 pthread_join(*tid_c, NULL)
pthread_create(&thread2, NULL, joinit, &thread1)
可以给出 thread2
一个有效的句柄(导致错误)。
如果您想让您的代码与现在类似,您需要添加某种锁以确保线程不会退出或过早地调用任何东西:
#include <stdio.h>
#include <pthread.h>
static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
void* joinit(void* tid)
{
/* this can be above the lock because it will be valid after lock is acquired */
pthread_t* tid_c = (pthread_t*)tid;
int retval = -1;
pthread_mutex_lock(&lock);
pthread_mutex_unlock(&lock);
printf("%#x waiting on %#x\n", pthread_self(), *tid_c);
retval = pthread_join(*tid_c, NULL);
printf("In joinit: tid = %d, retval = %d \n", *tid_c, retval);
return NULL;
}
int main()
{
pthread_t thread1;
pthread_t thread2;
/* get the lock in the main thread FIRST */
pthread_mutex_lock(&lock);
pthread_create(&thread1, NULL, joinit, &thread2);
pthread_create(&thread2, NULL, joinit, &thread1);
/* by this point, both handles are "joinable", so unlock */
pthread_mutex_unlock(&lock);
/* can wait on either thread, but must wait on one so main thread doesn't exit */
pthread_join(thread2, NULL);
return 0;
}
希望对您有所帮助。
错误的主要原因是您有两个线程,每个线程都在等待同一个线程终止,因为在 main
中调用了 pthread_join
。另一个问题是您不能确保每个线程都能正确看到另一个线程的 ID。
像这样修复它:
#include <stdio.h>
#include <pthread.h>
pthread_t thread1;
pthread_t thread2;
pthread_mutex_t mutex;
pthread_cond_t cond;
int go = 0;
void* joinit(void* ptr)
{
// wait until both thread IDs are known
pthread_mutex_lock(&mutex);
while (go == 0)
pthread_cond_wait(&cond, &mutex);
pthread_mutex_unlock(&mutex);
pthread_t* tid_c = *((pthread_t**) ptr);
printf("About to wait\n");
int retval = pthread_join(*tid_c, NULL);
printf("In joinit: tid = %d, retval = %d \n", *tid_c, retval);
// tell the other threads we're done
pthread_mutex_lock(&mutex);
go++;
pthread_cond_broadcast(&cond);
pthread_mutex_unlock(&mutex);
return NULL;
}
int main()
{
// setup synchronization
pthread_mutex_init(&mutex, NULL);
pthread_cond_init(&cond, NULL);
pthread_create(&thread1, NULL, joinit, &thread2);
pthread_create(&thread2, NULL, joinit, &thread1);
// tell the threads to go
pthread_mutex_lock(&mutex);
go = 1;
pthread_cond_broadcast(&cond);
pthread_mutex_unlock(&mutex);
// wait for both threads to finish
pthread_mutex_lock(&mutex);
while (go != 3)
pthread_cond_wait(&cond, &mutex);
pthread_mutex_unlock(&mutex);
return 0;
}
我正在寻找一个非常简单的示例来演示使用 pthread_join
的死锁;然而,这并非微不足道。
我是从这个开始的:
void* joinit(void* tid)
{
pthread_t* tid_c = (pthread_t*)tid;
int retval = pthread_join(*tid_c, NULL);
printf("In joinit: tid = %d, retval = %d \n", *tid_c, retval);
return NULL;
}
int main()
{
pthread_t thread1;
pthread_t thread2;
pthread_create(&thread1, NULL, joinit, &thread2);
pthread_create(&thread2, NULL, joinit, &thread1);
pthread_join(thread2, NULL);
return 0;
}
但是,它说 'EINVAL'(无效参数),因为在调用 thread1
的 pthread_create
时尚未指定 thread2
。
有什么想法吗?
如果您只是想证明 pthread_join
会导致死锁,您可以执行类似于以下代码的操作:
#include <stdio.h>
#include <pthread.h>
void* joinit(void* tid)
{
printf("In %#x, waiting on %#x\n", pthread_self(), (*((pthread_t*)tid)));
pthread_join((*((pthread_t*)tid)), NULL);
printf("Leaving %#x\n", pthread_self());
return NULL;
}
int main(void)
{
pthread_t thread1 = pthread_self();
pthread_t thread2;
pthread_create(&thread2, NULL, joinit, &thread1);
joinit(&thread2);
return 0;
}
这将导致主线程在派生线程上等待,而派生线程在主线程上等待(导致死锁),而不需要额外的锁定原语来扰乱您要演示的内容。
并更直接地回答您的一些问题:
it says 'EINVAL' (invalid argument) because
thread2
is not yet specified whenpthread_create
forthread1
is called.
...以及您的评论之一...
I tried this and it worked, but the problem is, it only works SOMETIMES because sometimes I get EINVAL again.
在您的代码中,您连续调用 pthread_create
以生成 2 个线程:
pthread_create(&thread1, NULL, joinit, &thread2);
pthread_create(&thread2, NULL, joinit, &thread1);
在您的 joinit
代码中,您获取传入的线程句柄以加入:
pthread_t* tid_c = (pthread_t*)tid;
int retval = pthread_join(*tid_c, NULL);
这个 有时 起作用的原因和你会得到 EINVAL
的其他原因与 time slices allocated to each thread's context and sequencing 有关。当第一个 pthread_create
被调用时,您将在 returns 之后有一个 thread1
的有效句柄,但 thread2
的句柄还无效,至少在第二个 pthread_create
被调用。
为此,当一个线程被创建时,线程的行为"alive"(即线程函数实际上运行)可能需要一些额外的时间,即使返回的线程句柄是有效的.在这些情况下,一个线程执行的代码可能比 "expected" 多。在你的代码中,两个 pthread_create
函数 可能 恰好在分配给主线程的时间片中被调用, 可以 给每个在命中 pthread_join
允许 tid_c
指向有效句柄的语句之前生成足够多的线程 "time";在 EINVAL
的情况下,调用 pthread_create(&thread1, NULL, joinit, &thread2)
并且生成的线程在 pthread_create(&thread2, NULL, joinit, &thread1)
之前命中 pthread_join(*tid_c, NULL)
pthread_create(&thread2, NULL, joinit, &thread1)
可以给出 thread2
一个有效的句柄(导致错误)。
如果您想让您的代码与现在类似,您需要添加某种锁以确保线程不会退出或过早地调用任何东西:
#include <stdio.h>
#include <pthread.h>
static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
void* joinit(void* tid)
{
/* this can be above the lock because it will be valid after lock is acquired */
pthread_t* tid_c = (pthread_t*)tid;
int retval = -1;
pthread_mutex_lock(&lock);
pthread_mutex_unlock(&lock);
printf("%#x waiting on %#x\n", pthread_self(), *tid_c);
retval = pthread_join(*tid_c, NULL);
printf("In joinit: tid = %d, retval = %d \n", *tid_c, retval);
return NULL;
}
int main()
{
pthread_t thread1;
pthread_t thread2;
/* get the lock in the main thread FIRST */
pthread_mutex_lock(&lock);
pthread_create(&thread1, NULL, joinit, &thread2);
pthread_create(&thread2, NULL, joinit, &thread1);
/* by this point, both handles are "joinable", so unlock */
pthread_mutex_unlock(&lock);
/* can wait on either thread, but must wait on one so main thread doesn't exit */
pthread_join(thread2, NULL);
return 0;
}
希望对您有所帮助。
错误的主要原因是您有两个线程,每个线程都在等待同一个线程终止,因为在 main
中调用了 pthread_join
。另一个问题是您不能确保每个线程都能正确看到另一个线程的 ID。
像这样修复它:
#include <stdio.h>
#include <pthread.h>
pthread_t thread1;
pthread_t thread2;
pthread_mutex_t mutex;
pthread_cond_t cond;
int go = 0;
void* joinit(void* ptr)
{
// wait until both thread IDs are known
pthread_mutex_lock(&mutex);
while (go == 0)
pthread_cond_wait(&cond, &mutex);
pthread_mutex_unlock(&mutex);
pthread_t* tid_c = *((pthread_t**) ptr);
printf("About to wait\n");
int retval = pthread_join(*tid_c, NULL);
printf("In joinit: tid = %d, retval = %d \n", *tid_c, retval);
// tell the other threads we're done
pthread_mutex_lock(&mutex);
go++;
pthread_cond_broadcast(&cond);
pthread_mutex_unlock(&mutex);
return NULL;
}
int main()
{
// setup synchronization
pthread_mutex_init(&mutex, NULL);
pthread_cond_init(&cond, NULL);
pthread_create(&thread1, NULL, joinit, &thread2);
pthread_create(&thread2, NULL, joinit, &thread1);
// tell the threads to go
pthread_mutex_lock(&mutex);
go = 1;
pthread_cond_broadcast(&cond);
pthread_mutex_unlock(&mutex);
// wait for both threads to finish
pthread_mutex_lock(&mutex);
while (go != 3)
pthread_cond_wait(&cond, &mutex);
pthread_mutex_unlock(&mutex);
return 0;
}