quantumshiv
quantumshiv

Reputation: 97

Segmentation fault / glibc detected when creating shared library

EDITS----------------I tried with gcc-4.8.1 and still the same error.-------------I am trying to implement a simple matrix multiplication example using pthreads via a shared library. But I get this error when I try to create a shared library:

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

Here is the code I am using: 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;

}

The commands that I use are: g++ -c -Wall -fPIC matmul.cpp -o matmul.o and g++ -shared -o libMatmul.so matmul.o The code might look little off because I am passing SIZE(dim) in a struct when its already in #define, but this is how I want it to be implemented. Its a test program for a bigger project that I am doing. Any help is greatly appreciated! Thanks in advance.

Upvotes: 1

Views: 1342

Answers (2)

txtechhelp
txtechhelp

Reputation: 6787

First, you're mixing a lot of C and C++ idioms (calling free and new for instance) and you're not using any C++ library/STL features (like a std::vector or std::list instead of a C array), so while your code is 'technically' valid (minus some bugs) it's not good practice to mix C and C++ like that, there are many small idiosyncratic differences between C and C++ (syntax, compilation and linkage differences for example) that can add confusion to the code if it's not explicitly clear to the intentions.

That being said, I've made some changes to your code to make it C++98 compatible (and fix the bugs):

start 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

start 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;
}

start 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;
}

To compile and use it you'll need to do the following commands:

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

Note that for your system to be able to find and link against the shared library you've just created, you'll need to ensure it's in your distro's lib folder (like /usr/lib/). You can copy/move it over, create a link to it (or a sym link via ln -s if you can't do hard links), and if you don't want to copy/move/link it, you can also ensure your LD_LIBRARY_PATH is properly set to include the build directory.

As I said; your code is NOT inherently C++ aside from the few print statements (std::cout, etc), and changing the C++ code (std::cout to printf and some other minor things for example) you could compile this as standard C99 code. I'm not 100% sure how the rest of your shared library will be designed so I didn't change the structure of the lib code (i.e. the functions you have) but if you wanted this code to be 'more C++' (i.e. with classes/namespaces, STL, etc.), you'd basically need to redesign your code, but given the context of your code, I don't think that's absolutely necessary unless you have a specific need for it.

I hope that can help.

Upvotes: 1

robby987
robby987

Reputation: 827

Should

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

not be

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

You created num_thrd threads, but did not join all of them, therefore, a race condition is created as you're trying to read the data before the thread is finished.

Upvotes: 0

Related Questions