Jump to content

Threads in Linux using c/c++ - Part 1

- - - - -

  • Please log in to reply
2 replies to this topic

#1
fayyazlodhi

fayyazlodhi

    Programming Expert

  • Members
  • PipPipPipPipPipPip
  • 403 posts
How to create and use Threads in C/C++ (POSIX threads) – Part 1


This is going to be a starting tutorial on how to use threads. It will only assume basics of c/c++ i.e. you know how to write a function and use variables, what is a basic pointer etc. you would be just fine.

The first thing to know is, there is no threading header / library available with the basic c/c++ compiler. So you need some extended one. That means you cannot create threads like “include <stdio.h>” and use printf(). You need to acquire a library first.

POSIX (Portable operating system interface) is a standard for API on all variants of Unix systems and contains a library called pthread. Unfortunately, it doesn’t run directly (at least) on windows and to use this code on windows you need something like
OpenMP.org

Thread issues have been asked around on the forum such as
http://forum.codecal...ix-threads.html

The below code is written and tested on Fedora Linux and I will try to keep it as basic as possible.

What are threads any way and why do we need them?

Ah… But I guess I should clarify the exact meaning and need for creating and using threads. Everyone would know the name though.

Generally when you write a program, there is a single path / flow of execution. Your code starts from first line of main and keep proceeding line by line towards the end of this function. But what if you have a need like for e.g. to read from screen whenever the user types AND print a message whenever it is received from network. If you simply try to accommodate both of these tasks in a simple main either you have to code reading from screen first or reading from network first. Even if these calls are non-blocking (it means program does not hang as in “cin” until you enter characters on the screen), still main would follow THE ORDER of execution of your statement i.e. reading from screen first and then latter reading from network. So your program will always be dependable on the order and the true meaning of it cannot be achieved in a single threaded main program.

A common solution is to create a new thread other than main. One of these two handles ‘reading from network’ where as the other ‘reads from console’.

A picture speaks for a thousand words. So here it goes.

Attached File  threads1.jpg   31.5K   278 downloads

Basic code details
The header file to include for threads is called “pthread.h”. This library is usually available on any Linux system. So you don’t have to worry about installing separately.

#include <iostream>

#include <pthread.h>


using namespace std;


void * thread_fun(void * param)

{

	cout << "Running thread" << endl;

	return param;

}


int main ()

{

	pthread_t thread_id;

        int param;


	cout << "testing basic c++" << endl;


        pthread_create(&thread_id, NULL, thread_fun, ¶m); 

	cout << "Running main after thread creation" << endl;

	return 0;

}


First we need to create a separate function which will be the starting point of thread i.e. it will be the code that is executed as a separate thread. We have a “thread_fun” here which takes a void * p as a parameter and return the same. This is required by definition of the API. Why? Because when you create a thread you most likely will need to pass some information to it and return something useful from it whenever you are making any practical application beyond just demo of how thread works. But obviously you could ignore the parameters if they are not needed as I have done in the code. The rationale of using a void pointer is that you should be able to pass anything. Any number of elements can be packed in a structure or an array and passed to thread where it can be interpreted.

In main we create a variable of type pthread_t which as it’s name indicates is a numeric value for a thread’s id. This will be similar to an integer which upon successful creation of a thread will contain the thread’s numeric id. Thread can be referred to using this id and this value serves as the basic point of identification for a thread.

Then is the call pthread_create, first parameter of which the same thread id mentioned already. The second one is a structure called thread_attr which can be used to create thread with specific values or configurations. Most of the times we pass a null which means create a thread with default values. You will see this utilized once you start playing around a little bit more with threads.

The next parameter is a function pointer to the function which is the starting point of thread. We pass “thread_fun” here as mentioned above. Please note that it will be a syntax error if thread fun’s signature (parameters and return values) do not match the one mentioned in code.

The last parameter can basically be the arguments passed to the thread. Currently we haven’t used it and just passed an integer without actually using it anywhere.

The return value of the thread function tells us if it was created successfully or there was any error.

How to Build and Execute

Assuming the source file’s name is thread.cpp, following is the command line
# g++ thread.cpp –o thread –lpthread
# ./thread

g++ is the compiler since I wrote c++ code. Gcc can be used too if written code is ANSI c. –o tells the compiler to name the binary executable file as “thread” which will be created in the current folder.
-lpthread is basically telling the compiler to link the exe with pthread library. Had we been using a header file such as “math.h” it would be –lm (because math.h’s should form is only m). If this linker statement is not added program would give linker error for not being able to locate the header file “pthread.h” and all of it’s definitions.

More functions to be used with Threads

pthread_self();
It returns a pthread_t object which basically is the thread id. So if you need current thread’s id inside the current thread, this function is helpful.


pthread_equal();
Takes two threads as parameters and returns 0 if both of their thread id’s are equal.

pthread_join();
A very very important function. It takes a thread id object and waits for the completion of that thread. For e.g. in the program above, there is no guarantee if main terminates first or the new thread. If you did some work in main AFTER creating the thread, and then once you are done with that work and you want to wait for the thread to complete before you exit main, you would use this function.

pthread_exit();
Can be used by a thread to force itself to terminate. Remember calling exit() would terminate the whole program.

pthread_cancel();
One thread can instruct another thread to terminate under specific circumstances. It takes a thread id object as parameter.

I will add some more code to above function in which we will pass some value to thread, do some operation, return a value from thread, and wait for thread termination in main where we read that value before exit.

#include <iostream>

#include <pthread.h>


using namespace std;


void * thread_fun(void * param)

{

	int value = *(int *)param; // Remember param is void pointer, so it needs to be casted into int BEFORE accessing value

                                   // Otherwise, there is no way for void pointer to know how many bytes to read when * is used.


	cout << "Param's value received in thread is: " << value  << endl;


        (*(int *)param)++; // increment param's value by 1

        return param;

}


int main ()

{

	pthread_t thread_id;

        int param = 10;

        void * t_status_void_p;

        int * thrd_status_ptr;

	int status;


	cout << "testing basic c++" << endl;


	status = pthread_create(&thread_id, NULL, thread_fun, ¶m); 


	if(status != 0)

		return -1;


        pthread_join(thread_id, &t_status_void_p); // note the status has to be a double pointer


        thrd_status_ptr =  (int *)t_status_void_p;


	cout << "Running main after thread's completion with value:" << *thrd_status_ptr  << endl;

	return 0;

}



I plan to extend more details and useful programs on threads if there is enough interest indicated by readers. I also intend to improve my previous TCP based concurrent server
http://forum.codecal...pi-linux-c.html
into truly concurrent server using threads.

Edited by fayyazlodhi, 26 July 2011 - 12:14 AM.
typos

Today is the first day of the rest of my life

#2
Guest

Guest

    Writes binary right handed and hex left handed

  • Members
  • PipPipPipPipPipPipPipPipPip
  • 3,414 posts
Ooh, great tutorial! I just have a couple of nitpicky things I want to say.

fayyazlodhi said:

There is a standard called POSIX (Portable operating system interface) which is the standard and is available on almost every Unix / Linux computer.
You made a redundancy error, and another error by saying "the standard" (as apposed to "a standard") the second time. Edit your post, cut a little off and it looks perfect!

Quote

There is a standard called POSIX (Portable operating system interface) which is available on almost every Unix / Linux computer.

Also, I would rather you choose C instead of C++ for the examples. There really is no right or wrong here, but I have a couple of good reasons.
  • *nix culture has sort of a de facto standard for using C as a compiled language, especially for small(ish), command line projects.
  • You did not using any features of the C++ language that make it worth using.
I know it really doesn't matter, but I have a strong personal preference for seeing pretty printfs instead of funky cout statements.

My commentary was sort of off-track, but nice tutorial anyway! I hope to see more like this. +rep

Root Beer == System Administrator's Beer
Download the new operating system programming kit! (some assembly required)

#3
fayyazlodhi

fayyazlodhi

    Programming Expert

  • Members
  • PipPipPipPipPipPip
  • 403 posts
Thanks for your valuable feedback Guest. I have fixed the typo in a (slightly) more useful manner.

As far as preferred usage of c, I personally work in the embedded domain when 99% code is c and there is a significant difference in my knowledge and experience of c vs c++ (i know c way much better).

I just opted for c++ because most of the student codes/queries i saw made me feel that majority has been using c++. I saw more questions regarding formatted output of cout compared to print / sprintf. So i thought it might be more convenient to a higher percentage of audience.

If this is not the case, i would be more than happy to write ANSI C. :)
Today is the first day of the rest of my life




1 user(s) are reading this topic

0 members, 1 guests, 0 anonymous users