【问题标题】:segmentation fault on pthread_mutex_initpthread_mutex_init 上的分段错误
【发布时间】:2014-01-28 19:16:35
【问题描述】:

我正在尝试使用线程池作为工作线程构建 TCP/IP 侦听器。 基本的东西不起作用,(cond_wait / cond_signal 麻烦)所以我正在缩小问题。但是使用下面的代码,我得到了一个分段错误。

struct worker {
    pthread_t      tid;
    pthread_cond_t worker_cv;
    pthread_mutex_t worker_mutex;
    int worker_flag;
};

typedef struct worker worker_t; 

void initialize_flag( worker_t * w)
{
    printf( "Mutex (%d)\n", (int) sizeof w->worker_mutex );
    pthread_mutex_init (& w->worker_mutex, NULL);
    printf( "Cond (%d)\n", (int) sizeof w->worker_cv );
    pthread_cond_init (& w->worker_cv, NULL);
    printf( "Flag\n" );
    w->worker_flag = 0;
}

SF 出现在“Mutex”的 printf 之后。 我传递给 initialize_flag() 的指针是一个全局指针,并在 main() 中进行了 malloc'ed,以模仿我正在寻找的真实行为。

TIA ((编辑:取自@marcelo的回答): 这是您要求的代码的相关部分

worker_t * worker;

main( )
{
    worker = malloc( sizeof( worker_t ) );

    if ( worker == NULL ) {
        fprintf( stderr, "malloc\n" );
        exit(1);
    }

    fprintf( stdout, "Zero\n" );

    memset( & worker, 0, sizeof( worker_t ) );

    fprintf( stdout, "Init\n" );

    initialize_flag( worker );

【问题讨论】:

  • 您可能想显示malloc()ing 和调用代码?
  • "%zu" 将是打印size_t 的正确格式。

标签: c segmentation-fault pthreads


【解决方案1】:

我看不出代码有什么问题,所以我想这可能是因为w->worker 没有指向 pthread_mutex_t 大小的内存块。

你没有显示initialize_flag 是如何被调用的,但它应该是这样的:

worker_t * w;
w = malloc(sizeof worker_t);
...
initialize_flag(w);

你说你已经在main() 中分配了这一切。我可以建议您这样做吗:

worker_t test;
initialize_flag(&test);

看看是否有segfaults?最好不要在main()做任何其他事情。

另外,我建议你在调试器中运行并打印出w->worker_mutex,或者做函数的第一行:

printf( "Mutex (%d:%p)\n", (int) sizeof w->worker_mutex, &(w->worker_mutex) );

【讨论】:

    【解决方案2】:

    代码通过将未分配的内存设置为零来引发未定义的行为:

    memset( & worker, 0, sizeof( worker_t ) );
    

    上面的行很可能是通过将sizeof(worker_t) bytes 写入worker_t bytes 所指向的指针的地址 来混合程序的内存管理分配,而不是指针指向的位置。

    这样做也会覆盖对内存分配的引用。它不再可访问,因此不能再被free()ed 并且程序泄漏此内存。

    要将新分配的结构清零:

    memset(worker, 0, sizeof(worker_t ));
    

    memset(worker, 0, sizeof(*worker));
    

    或使用calloc() 在分配时将其初始化为零(不再需要调用memset(worker, 0, ...)

    worker = calloc( 1, sizeof(worker_t));
    

    worker = calloc( 1, sizeof(*worker));
    

    您可能想知道为什么这里的代码还没有崩溃:

    printf( "Mutex (%d)\n", (int) sizeof w->worker_mutex );
    

    请注意,上面使用的sizeof(...) 表达式是在编译时计算的,因为它是常量。

    所以第 1st 时间(NULL-指针)w 正试图被取消引用:

    pthread_mutex_init (& w->worker_mutex, NULL);
    

    这样做会导致观察到的分割违规。

    【讨论】:

    • 你是对的:那个 memset() 是从以前版本的程序继承的,其中 worker 是一个自动(堆栈)变量,所以 & worker 是正确的。将工作人员移动到全局空间并将其更改为要分配的指针后,我忽略了“&”...
    【解决方案3】:
    memset( & worker, 0, sizeof( worker_t ) ); // zero worker
    

    不是

    一样
    memset( worker, 0, sizeof( worker_t ) ); // zero the objected worker designates
    

    您的memset 呼叫将在呼叫initialize_flag 之前立即将worker 设置为NULL

    这里根本不需要动态分配,只需要静态分配worker,初始会清零:

    worker_t worker;
    
    int main(void)
    {
        fprintf( stdout, "Init\n" );
        initialize_flag( &worker );
    

    【讨论】:

    • 当然,我知道将指针归零与将内存区域归零是不一样的。但是,请花点时间阅读 SIGSEV 是在初始化 worker 的 mutex 成员时。否则,您将时间浪费在徒劳的 cmets 上。谢谢大家。
    • @marcelo 是的,第一次取消引用刚刚创建的 NULL 指针时发生段错误是理所当然的。
    • "您的 memset 调用正在将 worker 设置为 NULL ...",它不仅将 worker 设置为 0,而且还设置了紧跟内存的 sizeof(*worker) - sizeof(worker) 字节worker 的存储位置。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-08-25
    • 1970-01-01
    • 1970-01-01
    • 2020-03-23
    • 2017-09-17
    • 2010-10-30
    • 2015-01-20
    相关资源
    最近更新 更多