【问题标题】:Segmentation fault / glibc detected when creating shared library创建共享库时检测到分段错误/glibc
【发布时间】:2014-03-04 18:31:35
【问题描述】:

EDITS----------------我用 gcc-4.8.1 试过了,还是一样的错误。-------------我正在尝试通过共享库使用 pthread 实现一个简单的矩阵乘法示例。但是当我尝试创建共享库时出现此错误:

g++ -shared -o libMatmul.so matmul.o 
collect2: ld terminated with signal 11 [Segmentation fault], core dumped

这是我正在使用的代码: matmul.h:

#ifndef matmul_h__
#define matmul_h__
#define SIZE 10 

typedef struct {

int dim;
int slice;
} matThread;

int num_thrd;
int A[SIZE][SIZE], B[SIZE][SIZE], C[SIZE][SIZE];
int m[SIZE][SIZE];
extern void init_matrix(int m[SIZE][SIZE]);
extern void print_matrix(int m[SIZE][SIZE]);
extern void* multiply(void* matThread);

#endif

matmul.c:

extern "C"
 {
    #include <pthread.h>
    #include <unistd.h>
 }
#include <iostream>
#include "matmul.h"

using namespace std ;
matThread* s=NULL;
// initialize a matrix
void init_matrix(int m[SIZE][SIZE])
{
  int i, j, val = 0;
  for (i = 0; i < SIZE; i++)
  for (j = 0; j < SIZE; j++)
  m[i][j] = val++;
}

void print_matrix(int m[SIZE][SIZE])
{
  int i, j;
  for (i = 0; i < SIZE; i++) {
    cout<<"\n\t|" ;
    for (j = 0; j < SIZE; j++)
      cout<<m[i][j] ;
      cout<<"|";
    }
}
 // thread function: taking "slice" as its argument
void* multiply(void* param)
{
  matThread* s = (matThread*)param;   // retrive the slice info
  int slice1=s->slice;
  int D= s->dim=10;
  int from = (slice1 * D)/num_thrd; // note that this 'slicing' works fine
  int to = ((slice1+1) * D)/num_thrd; // even if SIZE is not divisible by num_thrd
  int i,j,k;
   cout<<"computing slice  " << slice1<<" from row "<< from<< " to " <<to-1<<endl;
  for (i = from; i < to; i++)
  {  
    for (j = 0; j < D; j++)
    {
      C[i][j] = 0;
      for ( k = 0; k < D; k++)
      C[i][j] += A[i][k]*B[k][j];
    }
   }
  cout<<" finished slice "<<slice1<<endl;
  return NULL;
 }

main.c:

extern "C"
{
#include <pthread.h>
#include <unistd.h>
}
#include <iostream>
#include "matmul.h"
using namespace std;

// Size by SIZE matrices
// number of threads
matThread* parm=NULL;

int main(int argc, char* argv[])
{
  pthread_t* thread;  // pointer to a group of threads
  int i;
   if (argc!=2)
  {
   cout<<"Usage:"<< argv[0]<<" number_of_threads"<<endl;
   exit(-1);
  }
  num_thrd = atoi(argv[1]);
  init_matrix(A);
  init_matrix(B);
  thread = (pthread_t*) malloc(num_thrd*sizeof(pthread_t));
  matThread *parm = new matThread();
  for (i = 0; i < num_thrd; i++)
  {
parm->slice=i;
    // creates each thread working on its own slice of i
    if (pthread_create (&thread[i], NULL, multiply, (void*)parm) != 0)
    {
      cerr<<"Can't create thread"<<endl;
      free(thread);
      exit(-1);
    }
  }
 for (i = 1; i < num_thrd; i++)
  pthread_join (thread[i], NULL);
   cout<<"\n\n";
   print_matrix(A);
   cout<<"\n\n\t *"<<endl;
   print_matrix(B);
   cout<<"\n\n\t="<<endl;
   print_matrix(C);
   cout<<"\n\n";
   free(thread);

  return 0;

}

我使用的命令是: g++ -c -Wall -fPIC matmul.cpp -o matmul.o 和 g++ -shared -o libMatmul.so matmul.o 代码可能看起来有点不对劲,因为我在结构中传递了 SIZE(dim),而它已经在#define 中,但这就是我希望它实现的方式。它是我正在做的一个更大项目的测试程序。 任何帮助是极大的赞赏!提前致谢。

【问题讨论】:

  • 你使用的是什么版本的 GCC?
  • 我尝试使用 gcc 4.1,它让我创建了共享库,但无法将它与 main 链接。当我尝试使用 gcc-4.6.3 时,上面说的是错误
  • 我认为使用 pthread 时有一些编译器/链接器标志。像 -lpthread 之类的东西。
  • 使用 4.1 时,我可以创建共享库。当我执行命令时: g++ -L/dir.../ -Wall -o matmul main.cpp -lMatmul -ldl -lpthread 我得到了 glibc 检测到的错误。这又是某种内存错误映射和分段错误。
  • 使用gcc (Debian 4.4.5-8) 4.4.5至少可以成功创建库,如果使用选项-fPIC创建matmul.o。但是在创建多线程对象时,建议使用选项-pthread

标签: c++ multithreading segmentation-fault pthreads shared-libraries


【解决方案1】:

应该

 for (i = 1; i < num_thrd; i++)

不是

 for (i = 0; i < num_thrd; i++)

您创建了 num_thrd 个线程,但没有加入所有线程,因此,当您尝试在线程完成之前读取数据时,会创建一个竞争条件。

【讨论】:

  • 您创建了 num_thrd 个线程,但没有加入所有线程,因此,当您尝试在线程完成之前读取数据时,会创建竞争条件。
  • @robby987:我什至无法创建 .so 文件。上面的编辑是针对 main.c 文件的。我还尝试使用 -lpthread 标志来创建共享库,但仍然出现同样的错误
  • 我的作品。 '#!/bin/bash g++ -c -Wall -fPIC matmul.c -o matmul.o g++ -shared -o libMatmul.so matmul.o '
【解决方案2】:

首先,您混合了许多 C 和 C++ 习语(例如调用 freenew)并且您没有使用任何 C++ 库/STL 功能(例如 std::vectorstd::list而不是 C 数组),因此虽然您的代码在“技术上”是有效的(减去一些错误),但像这样混合 C 和 C++ 并不是一个好习惯,但 C 和 C++ 之间存在许多小的特殊差异(语法、编译和链接差异例如)如果没有明确的意图,这可能会给代码带来混乱。

话虽如此,我已经对您的代码进行了一些更改,以使其与C++98 兼容(并修复错误):

开始matmul.h:

#ifndef matmul_h__
#define matmul_h__
#define SIZE 10
#include <pthread.h>

typedef struct matThread {
    int slice;
    int dim;
    pthread_t handle;

    matThread() : slice(0), dim(0), handle(0) {}
    matThread(int s) : slice(s), dim(0), handle(0) {}
    matThread(int s, int d) : slice(s), dim(d), handle(0) {}
} matThread;

// explicitly define as extern (for clarity)
extern int num_thrd;
extern int A[SIZE][SIZE];
extern int B[SIZE][SIZE];
extern int C[SIZE][SIZE];
extern void init_matrix(int m[][SIZE]);
extern void print_matrix(int m[][SIZE]);
extern void* multiply(void* matThread);

#endif

开始matmul.cpp:

#include <iostream> // <stdio.h>
#include "matmul.h"

int num_thrd = 1;
int A[SIZE][SIZE];
int B[SIZE][SIZE];
int C[SIZE][SIZE];

// initialize a matrix
void init_matrix(int m[][SIZE])
{
    int i, j, val;
    for (i = 0, val = -1; i < SIZE; i++) {
        for (j = 0; j < SIZE; j++) {
            m[i][j] = ++val;
        }
    }
}

void print_matrix(int m[][SIZE])
{
    int i, j;
    for (i = 0; i < SIZE; i++) {
        std::cout << "\n\t|"; // printf
        for (j = 0; j < SIZE; j++) {
            std::cout << m[i][j];
        }
        std::cout << "|"; // printf
    }
}

// thread function: taking "slice" as its argument
void* multiply(void* param)
{
    matThread* s = (matThread*)param;   // retrive the slice info
    int slice1 = s->slice;
    int D = s->dim = 10;
    int from = (slice1 * D) / num_thrd; // note that this 'slicing' works fine
    int to = ((slice1+1) * D) / num_thrd; // even if SIZE is not divisible by num_thrd
    int i, j, k;
    std::cout << "computing slice " << slice1 << " from row " << from << " to " << (to-1) << std::endl; // printf
    for (i = from; i < to; i++) {
        for (j = 0; j < D; j++) {
            C[i][j] = 0;
            for ( k = 0; k < D; k++) {
                C[i][j] += A[i][k]*B[k][j];
            }
        }
    }
    std::cout << " finished slice " << slice1 << std::endl; // printf
    return NULL;
}

开始main.cpp:

#include <iostream>
#include <cstdlib> // atoi .. if C++11, you could use std::stoi in <string>
#include "matmul.h"

int main(int argc, char** argv)
{
    if (argc != 2) {
        std::cout << "Usage: " << argv[0] << " number_of_threads" << std::endl;
        return -1;
    } else {
        num_thrd = std::atoi(argv[1]);
    }
    matThread mt[num_thrd];
    int i = 0;
    init_matrix(A);
    init_matrix(B);
    for (i = 0; i < num_thrd; i++) {
        mt[i].slice = i;
        // creates each thread working on its own slice of i
        if (pthread_create(&mt[i].handle, NULL, &multiply, static_cast<void*>(&mt[i])) != 0) {
            printf("Can't create thread\n");
            return -1;
        }
    }
    for (i = 0; i < num_thrd; i++) {
        pthread_join(mt[i].handle, NULL);
    }
    std::cout << "\n\n";
    print_matrix(A);
    std::cout << "\n\n\t *\n";
    print_matrix(B);
    std::cout << "\n\n\t=\n";
    print_matrix(C);
    std::cout << "\n\n";
    return 0;
}

要编译和使用它,您需要执行以下命令:

g++ -c -Wall -fPIC matmul.cpp -o matmul.o
g++ -shared -Wl,-soname,libMatmul.so -o libMatmul.so.1 matmul.o
ln /full/path/to/libMatmul.so.1 /usr/lib/libMatmul.so
g++ main.cpp -o matmul -Wall -L. -lMatmul -pthread

请注意,为了让您的系统能够找到并链接到您刚刚创建的共享库,您需要确保它位于您的发行版的 lib 文件夹中(例如 /usr/lib/)。您可以复制/移动它,创建一个指向它的链接(或通过ln -s 的符号链接,如果你不能做硬链接),如果你不想复制/移动/链接它,你也可以确保您的 LD_LIBRARY_PATH 正确设置为包含构建目录。

正如我所说;除了少数打印语句(std::cout 等)和更改 C++ 代码(std::coutprintf 和其他一些小事情)之外,您的代码本质上不是 C++,您可以将其编译为标准 C99代码。我不是 100% 确定您的共享库的其余部分将如何设计,所以我没有更改 lib 代码的结构(即您拥有的函数)但如果您希望此代码“更多 C++”(即使用类/命名空间、STL 等),你基本上需要重新设计你的代码,但考虑到你的代码上下文,我认为这不是绝对必要的,除非你有特殊需要。

希望能帮到你。

【讨论】:

  • 非常感谢您在这里帮助我。但我仍然得到同样的错误!它仍然说 collect2: error: ld terminated with signal 11 [Segmentation fault], core dumped 。它为你编译了吗?我正在使用 gcc-4.8.1
  • OK 等等,它适用于 gcc 4.1.2。虽然不明白为什么!!无论如何,非常感谢您的帮助。是的,如果它的要求不高,你也能忍受 2 个线程的 C++ 吗?我只是想确定我在做什么。我认为调用pthread_create 时存在竞争条件,因为每当我调用 2 个线程时,只有最后一个线程处于活动状态。我认为mt.slice = i 在使用 0 的值之前会更新为 1。
  • 我确实知道 4.8.1 的一些更新“可能”使这个编译方式不同(作为共享库);我正在对此进行自己的研究,因为我使用了不同版本的 gcc,所以我会发布我发现的任何内容,说明为什么它可能无法在较新版本上编译。我也会稍微编辑一下我的帖子以添加 C++ 内容。
  • 我已将答案编辑为“更多 C++”,但请记住,您的代码并未真正使用任何“C++ 功能”(如答案中所述)。我还修复了导致线程跳过矩阵的“竞争”条件错误。请注意,此基于 C++ 的代码与我发布的基于 C 的原始代码之间没有太大的区别,但如果代码中的任何内容没有产生,请告诉我:)
  • 你就是那个男人!如果我认识你,我会请你吃午饭!非常感谢 :) 最后一个问题。有没有办法为切片创建一个数组而不是“结构数组”?说 slice[2] 在 struct 和 mt.slice[i] = i;如何在乘法函数定义中获取此值?
猜你喜欢
  • 2023-03-12
  • 2011-01-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-13
  • 1970-01-01
相关资源
最近更新 更多