2017-02-13 92 views
0

在函数last_letter() 行c = NULL将导致此程序在while(* c) 处发生段错误。什么原因?将字符指针设置为NULL并将其重新分配给它?我认为将指针设置为NULL并将其重新分配给其他内容是可以接受的?设置char *为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. 
} 
+3

如果将'c'设置为NULL,则其他线程*可能尝试使用'* c',而'c'为NULL。 – immibis

回答

1

您的变量c是全球性的,因此由所有主题共享。它在last_letter中使用,它有可能在同一时间在主线程和新线程中被调用。由于无法知道每个线程执行的顺序为last_letter,因此两者都可能是交错更改为c。所以当另一个线程期望它是一个有效值时,一个线程可以将它设置为NULL。

一个非常简单的方法很可能停止崩溃是睡眠和调用的顺序交换到last_letter在主线程

sleep(10); 
last_letter(s1, 5); 

此购买t1 10秒完成,这希望就足够了。更好的方法是在主线程中调用last_letter之前加入t1。但更好的方法是在last_letter之内移动c,因此每个线程都有一个唯一版本c,并且不会踩在其他线程的脚趾上。如果必须共享c,则需要使用互斥锁来保护它。

这样你就不需要主执行last_lettert1也执行它。由于main和t1在不同的数据上运行,也不会改变这些数据,所以它是安全的。

虽然你仍然想在t1上调用join,否则主可能会在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. 
} 
4

首先,这是一个经典的竞赛条件。该程序取决于调用aa()的顺序。

的最后一个参数pthread_create()是参数。从手册页:

int pthread_create(pthread_t *thread, const pthread_attr_t *attr, 
        void *(*start_routine) (void *), void *arg); 

所以当AA()通过并行线程机制被调用时,一个参数为NULL,因为在pthread_create()是带一个NULL ARG。

那么这个循环取消引用一个NULL指针,导致飞机坠毁:

c = a; 
sleep(i); 
while (*c) { 
    c++; 
} 

所以给在pthread_create()非NULL参数和你在一个更好的轨道。