Inferno Web Development
  • Home
  • Forums
  • About
  • Links
  • Contact

Tutorials List

  • C++ Tutorials

Articles

  • Java
  • PHP
  • Photoshop
  • C#
  • C++ Qt GUI
  • C++ Win32 API
  • C++
  • MASM32
  • General News
  • JavaScript
  • Web Development
  • Windows Tweaks

Popular Tutorials

All time:

  • Website Header with 3D Fold Up / Lift Effect
  • C++ Win32 API Tutorial
  • Perfect C++ String Explode Split
  • Simple C++ DLL Loading a Message Box
  • Simple C++ Pointers and References

Related Articles

  • Beginner C++ Cout Cin Integer
  • Singleton C++
  • C++ Volatile Keyword
  • Perfect C++ String Explode Split
  • C/C++ Basic Structures of a Simple Program

Programming Tutorials

Home

C++ Pthreads API

Submitted by Baran Ornarli on Sun, 11/09/2008 - 23:50.
  • C++

Table of Contents

  1. Matrix class
  2. thread_data Structure, for Thread Arguments
  3. pthread_t structure
  4. pthread_attr_t attribute structure
  5. pthread_create function
  6. pthread_join thread function
  7. CalcMatrix function
  8. Reminder

Ever created a multi-threaded application? Using POSIX threads, called Pthreads you can create multi-threaded applications in almost any operating system. Pthreads give you the ability to control threads using C++. In this example, we will create a multi-threaded Matrix Multiplication Application.

I will be using pthreads, but you have the option of defining how I get our Matrix input, I used two files.

The following code can only run under Linux, though it will run under Windows with the required library like pthreads-w32.

Note: You may replace any qstring or q_ function with any function of your choice that does the same thing. For qstring, you can use string std class. For qDebug() you can replace it with std cout.

int main(int argc, char** argv){
    int rc, status;
    if(argc > 3){ // Make sure there is 3 arguments.
        Matrix M = readMatrix(argv[1]); // Read the first input file, store it as Matrix M 
        Matrix N = readMatrix(argv[2]); // Read the 2nd input file, store it as Matrix N
        QString Results(argv[3]); // Get output file name
        if(M.columns != N.rows){ // Cannot multiply matrices if the first one's columns are not equal to the second one's rows
            qDebug() << "Error: Cannot multiply these two matrices";
            return 0;
        }
        pthread_t threads[(N.columns*M.rows)]; // Create a pthread_t
        pthread_attr_t attr; // Create attribute for pthread
         /* Initialize and set thread detached attribute */
        pthread_attr_init(&attr); // initialize attribute
        pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); // make the attribute have JOINABLE option
        C = new Matrix; // Resulting C matrix
        C->rows = M.rows; // set result rows equal to the first matrix's row
        C->columns = N.columns; // set result column equal to the second matrix's column
        int t = 0;
        for(int r = 0; r < M.rows; r++){ // Loop rows 1st Matrix
            for(int c = 0; c < (N.columns); c++) { // Loop columns 2nd Matrix
                for(int i = 0; i < M.columns; i++){ // Loop columns 1st Matrix
                    thread_data_array[t].thread_a_row[i] = M.V[r][i]; // Get first matrices row
                } 
                for(int i = 0; i < N.rows; i++){ // Loop rows 2nd Matrix
                    thread_data_array[t].thread_b_column[i] = N.V[i][c]; // Get second matrices rows
                } 
                thread_data_array[t].thread_id = t; // set thread id
                thread_data_array[t].a = M.columns; // set first matrix's columns as a
                thread_data_array[t].b = N.rows; // set second matrix's rows as b
                rc = pthread_create(&threads[t], &attr, calcMatrix, (void *) &thread_data_array[t]); // Create Thread
                // Set pthread_t, then attribute attr, then calcMatrix our calculating function, give it the argument struct.
                if (rc) { // if there is an error
                    qDebug() << "ERROR: " << rc << endl;
                    exit(-1);
                }
                /* Free attribute and wait for the other threads */
                t++; // increment thread
            }
        }
        pthread_attr_destroy(&attr); // destroy the attribute.
        int thr = 0;
        for(int r = 0; r < M.rows; r++){
            for(int c = 0; c < N.columns; c++){
                rc = pthread_join(threads[thr], (void **)&status); // Wait for the thread to end and join this function
                if (rc) { // check for error
                     qDebug() << "ERROR join";
                     return 0;
                }
                C->V[r][c] = 0;
                for(int i = 0; i < N.rows; i++){ // Get the result of that one matrix multiplication
                    C->V[r][c] = thread_data_array[thr].x;
                }
                thr++;
            }
        }
        // You can replace qDebug() with cout, and qPrintable isn't important.
        qDebug() << "Results recorded to " << Results << ": ";
        qDebug() << qPrintable(PrintMatrix(C)); // Print results on screen
        pthread_exit(NULL); // exit thread
    } else {
        qDebug() << "Please include the first matrix file, the second matrix file, and the output file in order for this program's arguments."; // in case there is an error
    }
 
    return 0;
}

We first check for our arguments in command line, get out 2 Matrix classes.

Matrix class

Our Matrix classes look like this:

class Matrix {
public:
    int V[30][30];
    int rows;
    int columns;
}; // a simple matrix class
 
Matrix* C = 0;

The V represents our variables in rows and columns as a 2 dimensional array.

thread_data Structure, for Thread Arguments

Our thread_data class looks like this, it contains arguments for our threads, you can edit it as much as you want:

struct thread_data
{
   int	thread_id;
   int thread_a_row[30];
   int thread_b_column[30];
   int x;
   int a;
   int b;
};
 
struct thread_data thread_data_array[20];

pthread_t structure

pthread_t threads[(N.columns*M.rows)];, this will create a number of threads that we will be using in our calculation function.

pthread_attr_t attribute structure

pthread_attr_t attr; // Create attribute for pthread
         /* Initialize and set thread detached attribute */
        pthread_attr_init(&attr); // initialize attribute
        pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); // make the attribute have JOINABLE option

We set our attribute for our threads as PTHREAD_CREATE_JOINABLE, which means we can use pthread_join() to combine each thread with the main thread, and wait for it to do this. This allows us to sync our threads back to a single thread.

We create our Resulting Matrix C, which is our answer, and we add our arguments for each calcMatrix thread using thread_data_array.

pthread_create function

rc = pthread_create(&threads[t], &attr, calcMatrix, (void *) &thread_data_array[t]); // Create Thread

We create each thread, add our attribute, add our calcMatrix (which is a function not a variable), and our argument thread_data_array, which has all our variables.

pthread_attr_destroy(&attr); // destroy the attribute.
Free the attribute.

pthread_join thread function

rc = pthread_join(threads[thr], (void **)&status); // Wait for the thread to end and join this function

This will join each thread to the main thread, so that we are synced up.

C->V[r][c] = thread_data_array[thr].x;
Add our results into our resulting matrix class.

pthread_exit(NULL); // exit thread
Exit the thread

CalcMatrix function

Here's our calcMatrix function:

void *calcMatrix(void *threadarg) { // calculate Matrix multithreaded function 
   int taskid;
   struct thread_data *my_data;
 
   sleep(1); // Sleep 1 ms to not overburden the CPU
   my_data = (struct thread_data *) threadarg; // Get the argument structure
   taskid = my_data->thread_id;
   my_data->x = 0;
   for(int i = 0; i < my_data->a; i++) { // loop through until a is finished
     my_data->x += my_data->thread_a_row[i]*my_data->thread_b_column[i]; // multiply and add together
   }
   pthread_exit(NULL); // exit thread
}

calcMatrix is going to be provided to each thread to use as a function. It will grab our thread_data from arguments, multiply the variables. Exit the pthread.

Reminder

Remember to #include <pthread.h>


5
Average: 5 (2 votes)
»
  • Share Tutorial

Post new comment

The content of this field is kept private and will not be shown publicly.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Allowed HTML tags: <a> <em> <strong> <cite> <code> <img> <ul> <ol> <li> <dl> <dt> <dd> <h3> <h4> <h2>
  • Lines and paragraphs break automatically.
  • Image links with 'rel="lightbox"' in the <a> tag will appear in a Lightbox when clicked on.
  • You can enable syntax highlighting of source code with the following tags: <code>, <blockcode>. Beside the tag style "<foo>" it is also possible to use "[foo]".
  • You can use BBCode tags in the text. URLs will automatically be converted to links.
  • Table of contents based on the <h*> tags

More information about formatting options

CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.
 ooooo      ooo    .oooo.                                                      
`888b. `8' .dP""Y88b
8 `88b. 8 ]8P' .oooooooo .ooooo. oooo d8b oooo oooo ooo
8 `88b. 8 <88b. 888' `88b d88' `"Y8 `888""8P `88. `88. .8'
8 `88b.8 `88b. 888 888 888 888 `88..]88..8'
8 `888 o. .88P `88bod8P' 888 .o8 888 `888'`888'
o8o `8 `8bd88P' `8oooooo. `Y8bod8P' d888b `8' `8'
d" YD
"Y88888P'
Enter the code depicted in ASCII art style.

Navigation

  • Home
  • Forums
  • Image Gallery
  • Links
  • About
  • Contact

Why Register? Contribute articles and tutorials to ID, earn titles, learn from ID programming projects, and advertise your blog in our forums.

  • Forum Community
  • Register Now
  • Write an Article


Copyright © Inferno Development 2008-2009. All Rights Reserved.