在函数last_letter()中 行c = NULL将导致此程序在while(* c)处发生段错误 评论它不会。什么原因?将char指针设置为NULL并重新分配给它?我认为将指针设置为NULL并将它们重新分配给其他东西是可以接受的吗?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
char s1[] = "abcdefg";
char s2[] = "xyz";
char* c;
void last_letter(char* a, int i) {
printf("last_letter ( a is %s and i is %d)\n", a, i);
sleep(i);
c = NULL; // comment out, what is different?
sleep(i);
c = a;
sleep(i);
while (*c) {
c++;
}
printf("%c\n", *(c-1));
return;
}
// This function will run concurrently.
void* aa(void *ptr) {
last_letter(s2, 2);
return NULL;
}
int main() {
pthread_t t1;
int iret1 = pthread_create(&t1, NULL, aa, NULL);
if (iret1) {
fprintf(stderr,"Cannot create thread, rc=%d\n", iret1);
}
last_letter(s1, 5);
sleep(10);
printf("Ended nicely this time\n");
return 0; //never reached when c = NULL is not commented out.
}
答案 0 :(得分:4)
首先,这是一个经典的竞争条件。该程序取决于调用aa()的顺序。
pthread_create()的最后一个参数是参数。从联机帮助页:
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg);
因此,当通过pthread机制调用aa()时, a 参数为NULL,因为使用NULL arg调用 pthread_create()。
然后这个循环取消引用NULL指针,导致崩溃:
c = a;
sleep(i);
while (*c) {
c++;
}
所以给 pthread_create()一个非NULL参数,你的轨道就更好了。
答案 1 :(得分:1)
您的变量c
是全局的,因此所有线程都共享。它在last_letter
中使用,它可以同时在主线程和新线程中被调用。由于无法知道每个线程执行last_letter
的顺序,因此两者都可以将更改交错到c
。因此,当另一个线程期望它是有效值时,一个线程可以将其设置为NULL。
一种非常简单的方法可以阻止崩溃,即在主线程中将睡眠顺序和调用交换为last_letter
sleep(10);
last_letter(s1, 5);
这将花费t1
10秒完成,这有望足够了。更好的方法是在主线程中调用t1
之前加入last_letter
。然而,更好的方法是将c
移到last_letter
内,因此每个线程都有c
的唯一版本,并且不会踩到其他线程的脚趾。如果必须共享c
,则需要使用互斥锁保护它。
这样你就不需要阻止主执行last_letter
而t1
也执行它。由于main和t1
对不同的数据进行操作,并且不会改变这些数据,因此非常安全。
您仍然希望在join
上调用t1
,否则主文件可能会在t1
完成之前完成并退出。
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
char s1[] = "abcdefg";
char s2[] = "xyz";
void last_letter(char* a, int i) {
char* c;
printf("last_letter ( a is %s and i is %d)\n", a, i);
sleep(i);
c = NULL; // pointless but if you must
sleep(i);
c = a;
sleep(i);
while (*c) {
c++;
}
printf("%c\n", *(c-1));
}
// This function will run concurrently.
void* aa(void *ptr) {
last_letter(s2, 2);
return NULL;
}
int main() {
pthread_t t1;
int iret1 = pthread_create(&t1, NULL, aa, NULL);
if (iret1) {
fprintf(stderr,"Cannot create thread, rc=%d\n", iret1);
return 0;
}
last_letter(s1, 5);
pthread_join(t1, NULL); // should check return value in production code
printf("Ended nicely this time\n");
return 0; //never reached when c = NULL is not commented out.
}