我们有以下代码行:
printf("%d\n", toc->runlist.next);
printf("%d\n", toc->runlist.next);
这些是定义:
typedef struct thread_overview_control{
int id[NR_UTHREADS];
list_t runlist;
int active_counter;
int main_thread;
int need_resched;
} thread_overview_control;
thread_overview_control* toc;
我要做的是实现用户线程。出于某种原因,上面代码在我们的测试运行压缩点的输出是:
12345678 //some address
0 //NOW IT'S NULL?!?!?!
怎么会发生这种情况?我们所做的只是读取一个变量。 奇怪的是,没有printf就没有崩溃。发生了什么事?
答案 0 :(得分:3)
很可能另一个线程正在访问(和更改)两次调用printf()之间的变量。如果删除printf语句,时间会发生变化,行为也会不同。
如果多个线程确实正在访问数据,则需要使用互斥锁保护它。
答案 1 :(得分:1)
printf()
不会修改其可变参数。但是,printf()
是一个成本足以暴露线程之间没有(或不正确)锁定引起的竞争的操作。
您要使用的是互斥锁:
pthread_mutex_t thread_lock = PTHREAD_MUTEX_INITIALIZER;
void *thread_func(void *threadarg)
{
thread_overview_control *toc = (thread_overview_control *)threadarg;
pthread_mutex_lock(&thread_lock);
printf("%d\n", toc->runlist.next);
printf("%d\n", toc->runlist.next);
pthread_mutex_unlock(&thread_lock);
....
在该示例中,pthread_mutex_lock()
将阻止另一个线程是否具有锁定。如果您的函数在等待锁定可用时可以执行其他有用的工作,请尝试pthread_mutex_trylock()
,也许在while()
循环中。
确保每个线程都可以通过使其成为全局(或将其置于每个可以访问的结构中)来访问互斥锁。使用PTHREAD_MUTEX_INITIALIZER
初始化互斥锁同样重要,否则您将面临锁定的风险,而没有任何线程实际持有它。
每当您阅读或写信*toc
时,您都需要获得锁定。
答案 2 :(得分:1)
尝试在valgrind下运行您的程序。它会指出您可能遇到的任何与内存相关的错误。
答案 3 :(得分:1)
虽然竞争条件是一个可能的原因,但听起来你的问题比我希望看到的解释更加一致。
另一种可能性是一个普通的旧野指针。你是如何初始化toc
的?如果它最终指向已释放的堆栈内存,则第一个printf()
调用很容易踩到它。
答案 4 :(得分:0)
什么是list_t
?这是普通的C吗?请注意,在C ++中可以simulate a "property"(有点),因此调用runlist.next
实际上会调用某个方法,它可能是伪装的迭代器。