2

My question is related to thread programming in C.

My problem is that I just want to create two threads in my main program. These two threads should work sequentially, which means my first thread should execute first (no other statement of any thread should be executed). First thread should have complete control. No other statement of any other thread, even main program statements, should be executed until the first thread is complete.

After completion of the first thread, the second thread should be executed in a similar way as the first.

After that my main should execute.

I know you can say why the hell I want to do this, because this thing can be achieved by just creating two functions and calling them in sequence, but for learning and for experimentation I want to do it with the help of threads.

I write some code in C as follows:

void* fun()
{ 
 printf("\nThe thread 1 is running");
}
void* van()
{
 printf("\nthread 2 is running ");
}
int main()
{
 pthread_t t1,t2;
 pthread_create(&t1,NULL,fun,NULL);
 pthread_create(&t2,NULL,van,NULL);
 printf("\nI'm in main\n");
 pthread_join(t2,NULL); 
}

The program is working perfectly but I don't understanding the working of the function pthread_join().

When I change my code a little bit as follows:

int main()
{
 pthread_t t1,t2;
 pthread_create(&t1,NULL,fun,NULL);
 pthread_join(t2,NULL); // Change
 pthread_create(&t2,NULL,van,NULL);
 printf("\nI'm in main\n");
}

Now when I run the code it shows a segmentation fault.

Now my questions are the following:

  1. What is the attribute parameter in the pthread_create() function? Why do we use them? What are the default attributes for a thread? Please explain with an example.
  2. What is the argument in pthread_create() function? Why we use them? What are the default arguments for a thread? Please explain with an example.
  3. How does pthread_join() work actually? What does it mean when my code calls pthread_join() in main with t2 as first argument. Does it mean main should suspend its execution until t2 execution has completed or something else?
  4. What is the second argument in pthread_join()? Why do we use it? What is its default value? Please explain with an example or code.
kangaroo_cliff
6,2523 gold badges33 silver badges45 bronze badges
asked Jun 3, 2011 at 5:12
1
  • 1
    Your thread functions should return a value, even if it is just zero, so that they return a null void pointer. In the 'working' code, it is pure coincidence that it sequences as you intend. The two thread functions execute concurrently; main() does not wait for thread 1 to complete before launching thread 2. If you waited for thread 1 to complete (pthread_join(&t1, NULL); after its pthread_create(), that would minimize the concurrent execution. Repeat for thread 2. Then you can run the printf() in main() itself. Since you've already waited for each thread to complete, you're done. Commented Jun 3, 2011 at 5:49

4 Answers 4

7
  1. The attr argument points to a pthread_attr_t structure whose contents are used at thread creation time to determine attributes for the new thread; this structure is initialized using pthread_attr_init(3) and related functions. If attr is NULL, then the thread is created with default attributes (source).

  2. Argument is passed to your thread function. This is the best way of passing data to the thread (as opposed to using global variables, e.g.).

  3. Yes, pthread_join waits until the thread finishes. That's why your program fails when you call pthread_join before you start the thread, since t2 contains junk at that point.

  4. If retval is not NULL, then pthread_join() copies the exit status of the target thread (i.e., the value that the target thread supplied to pthread_exit(3)) into the location pointed to by *retval. If the target thread was canceled, then PTHREAD_CANCELED is placed in *retval. (source).

I.e., you can make your thread function to notify you about its execution result.

Given this, your thread creation may look like this:

struct th_arg{
 ...
};
static void th_work(struct th_arg* a){
 //...some work
 if (success) pthread_exit(EXIT_SUCCESS)
 else pthread_exit(ERROR_CODE);
}
int main(){
 int t1,t2;
 struct th_arg[2];
 int codes[2];
 // initialize th_arg2 
 pthread_create(&t1, NULL, th_work, th_arg+0, th_arg+0);
 pthread_create(&t2, NULL, th_work, th_arg+1, th_arg+1);
 pthread_join(t1, codes+0);
 pthread_join(t2, codes+1);
 if (codes[0] == EXIT_SUCCESS && codes[1] == EXIT_SUCCESS){
 ...
 }
} 
Jonathan Leffler
758k145 gold badges958 silver badges1.3k bronze badges
answered Jun 3, 2011 at 5:21
2

Best source to learn posix threads is https://computing.llnl.gov/tutorials/pthreads/

answered Jun 3, 2011 at 5:22
1
  • The attribute in pthread_create is of type pthread_attr_t. It holds information about the thread, including things like where the thread's memory address starts and how large its stack can get. Most of the time you won't need to use this parameter.

  • The arg in pthread_create is passed to the start_routine function as the one and only argument. This is kind of a hack. Since a pointer can point at anything (an int, an array, a struct, etc), you can pass in your arguments by passing a pointer to ALL of the data you want to pass in. Most of the time people end up going with a struct. There are no default arguments for a thread. If you don't want to pass anything in, just specify arg as NULL.

As an example:

struct arguments
{
 int something;
 char* anotherArg;
 short stillAnotherArg;
}
void* fun(void* arg)
{
 struct arguments *my_args = (struct arguments*)arg;
 printf("You said: %s\n", my_args->anotherArg); // Will print "You said: Hello there"
 ...
}
int main()
{
 pthread_t t1;
 struct arguments my_args;
 my_args.something = 5;
 my_args.anotherArg = "Hello there";
 my_args.stillAnotherArg = 42;
 pthread_create (&t1,NULL,fun, &my_args);
 ...
}
  • pthread_join blocks the caller until the specified thread has finished.

  • The second argument to pthread_join allows you to capture the return value of the thread once it's done executing. Each of your threads returns a void*, and the second parameter allows you to specify where that return value gets stored.

As an example:

void* fun(void* arg)
{
 ...
 return NULL; // not very exciting, but I don't want to get
 // into memory management problems right now
}
int main()
{
 ...
 void* theReturnValue;
 pthread_join(t2, &theReturnValue);
 printf("fun returned %p\n", theReturnValue); // will print "fun returned 0x0"
 // which is NULL
}

Finally, the reason it segfaults is because you're waiting for a thread that hasn't been defined yet.

answered Jun 3, 2011 at 5:30
1

You can use omp library by including omp.h. It is easy to use. You can create a parallel section with the directive

#pragma omp parallel
{
 // PARALLEL Code
}

And setting thread numbers with omp_set_num_threads(2); and then get the id of a thread with omp_get_thread_num();

Example:

omp_set_num_threads(2);
#pragma omp parallel
{
 printf("thread %d said hello", omp_get_thread_num());
}
Mihai Chelaru
8,45215 gold badges49 silver badges53 bronze badges
answered Jun 3, 2018 at 2:59

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.