Thread: threads inside threads problem

  1. #1
    Registered User
    Join Date
    Aug 2014
    Posts
    2

    threads inside threads problem

    So I'm working on multipling 2 matrices in C++ using threads.
    This is the code:
    Code:
    #include<iostream>#include<cstdlib>
    #include<pthread.h>
    using namespace std;
    
    
    const int m=5;
    const int n=4;
    const int s=4;
    const int r=6;
    const int num_thrd_row=2;
    const int num_thrd_col=3;
    
    
    class data
    {
    public:
      int* A;
      int* B;
      int* C;
      int start;
      int row;
      int column;
      data(int* a,int* b,int* c): A(a),B(b),C(c),start(0) {}
    };
    
    
    void* multiply_columns(void* dat)
    {
      data* P=(data*)dat;
      int i=P->row;
    
    
      for(int j=P->column;j<r;j+=num_thrd_col)//***problem***
      {
        float sum=0;
    
    
        for(int k=0;k<s;k++)
          sum+=P->A[i*n+k]*P->B[k*r+j];
    
    
        P->C[i*r+j]=sum;
      }
    }
    
    
    void* multiply_rows(void* dat)
    {
      data* P=(data*)dat;
      pthread_t tID[m*num_thrd_col];
    
    
      for(int i=P->start;i<m;i+=num_thrd_row)
      {
        P->row=i;
        P->column=0;
    
    
        for(int t=0;t<num_thrd_col;t++)
        {
          pthread_create(&tID[i*num_thrd_col+t],NULL,multiply_columns,(void*)P);
          P->column++;//***problem***
        }
    
    
        for(int t=0;t<num_thrd_col;t++)
          pthread_join(tID[i*num_thrd_col+t],NULL);
      }
    }
    
    
    int main()
    {
      srand(time(NULL));
    
    
      int* A=new int[m*n];
      int* B=new int[s*r];
    
    
      for(int i=0;i<m*n;i++)
        A[i]=rand()%10+1;
    
    
      for(int i=0;i<s*r;i++)
        B[i]=rand()%10+1;
    
    
      if(n==s)
      {
        int* C=new int[m*r];
        pthread_t tID[num_thrd_row];
    
    
        data* P=new data(A,B,C);
    
    
        for(int i=0;i<num_thrd_row;i++)
        {
          pthread_create(&tID[i],NULL,multiply_rows,(void*)P);
          P->start++;
        }
    
    
        for(int i=0;i<num_thrd_row;i++)
          pthread_join(tID[i],NULL);
    
    
        cout << "A [" << m << "*" << n << "]=" << endl;
        for(int i=0;i<m*n;i++)
        {
          cout << A[i] << "\t";
          if((i+1)%n==0) cout << endl;
        }
    
    
        cout << endl << "B [" << s << "*" << r << "]=" << endl;
        for(int i=0;i<s*r;i++)
        {
          cout << B[i] << "\t";
          if((i+1)%r==0) cout << endl;
        }
    
    
        cout << endl << "AB [" << m << "*" << r << "]=" << endl;
        for(int i=0;i<m*r;i++)
        {
          cout << C[i] << "\t";
          if((i+1)%r==0) cout << endl;
        }
    
    
        delete[] C;
      }
      else
        cout << "Matrices cannot be multiplied!" << endl;
    
    
      delete[] A;
      delete[] B;
    
    
      return 1;
    }
    Problem is, "j=P->column", because j is always equal to 3.
    How can that be possible? In main thread is done the same thing (with P->start, and "i=P->start" works just fine. Thanks for your help.

  2. #2
    Registered User
    Join Date
    Jun 2005
    Posts
    6,815
    You need to read up on threads properly, because you are completely misinterpreting how they work.

    If multiple thread threads act on the same data concurrently, the result is a race condition (anything can happen, depending on which thread affects the data when, whether the operating system causes threads to preempt each other). Threads do not self-synchronise amongst themselves.

    In your calls of pthread_create(), you are providing the same pointer (P) to every thread. That means all threads act on the same data concurrently.

    Either your threads need to be passed different data (e.g. each thread is passed its own P, which is not shared with other threads) or they need to synchronise access to it (e.g. each thread cooperates with every other thread, and waits until it has exclusive access to the data) using synchronisation primitives (mutexes, critical sections, etc).
    Right 98% of the time, and don't care about the other 3%.

    If I seem grumpy or unhelpful in reply to you, or tell you you need to demonstrate more effort before you can expect help, it is likely you deserve it. Suck it up, Buttercup, and read this, this, and this before posting again.

  3. #3
    Registered User
    Join Date
    Aug 2014
    Posts
    2
    I tried this before, and it still didnt work, and I also tried mutex to try to see what is the problem, and even with mutex, j=P->column was always 3.
    Code:
    void* multiply_rows(void* dat)
    {
      data* P=(data*)dat;
      data* P_new=new data(P->A,P->B,P->C);
      pthread_t tID[m*num_thrd_col];
    
    
      for(int i=P->start;i<m;i+=num_thrd_row)
      {
        P_new->row=i;
        P_new->column=0;
    
    
        for(int t=0;t<num_thrd_col;t++)
        {
          pthread_create(&tID[i*num_thrd_col+t],NULL,multiply_columns,(void*)P_new);
          P_new->column++;
        }
    
    
        for(int t=0;t<num_thrd_col;t++)
          pthread_join(tID[i*num_thrd_col+t],NULL);
      }
    }

  4. #4
    Registered User
    Join Date
    Jun 2005
    Posts
    6,815
    There is no guarantee that a created thread executes (calls the supplied function) before pthread_create() returns. My previous comments still stand.
    Right 98% of the time, and don't care about the other 3%.

    If I seem grumpy or unhelpful in reply to you, or tell you you need to demonstrate more effort before you can expect help, it is likely you deserve it. Suck it up, Buttercup, and read this, this, and this before posting again.

  5. #5
    Registered User MutantJohn's Avatar
    Join Date
    Feb 2013
    Posts
    2,665
    Also, C++11 changed how we do threads and tbh, it's entirely for the better.

    Instead, using std::thread and lambda functions (Lambda functions (since C++11) - cppreference.com).

    A good thing to do is to create a vector like so :
    Code:
    std::vector<std::thread> threads;
    threads.emplace_back([/* captures (what your functions need) */](parameters)->return_type
    {
    /* ... */
    })
    
    for (auto &t : threads)
        t.join()
    I'm not sure if that's confusing or not but to me, it was always simplest to just see exactly what code each thread would be running. Note that you can capture pretty much everything into your lambdas and you can pretty much call anything with them too. I think they simplify the threading model greatly.

    I also believe valgrind comes with multithreaded support now or at least it comes with a data race detector : Valgrind
    Last edited by MutantJohn; 08-22-2014 at 09:09 AM.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 22
    Last Post: 12-14-2012, 11:00 AM
  2. Threads , how? Portable Threads Library?
    By adderly in forum C++ Programming
    Replies: 3
    Last Post: 12-15-2011, 07:54 AM
  3. a point of threads to create multiple threads
    By v3dant in forum C Programming
    Replies: 3
    Last Post: 10-06-2004, 09:48 AM
  4. problem using threads......?
    By stumpert in forum C++ Programming
    Replies: 1
    Last Post: 04-28-2002, 07:37 AM
  5. Threads problem
    By Barjor in forum Windows Programming
    Replies: 2
    Last Post: 03-13-2002, 10:06 AM