码迷,mamicode.com
首页 > Windows程序 > 详细

Operating System: Three Easy Pieces --- Thread API (Note)

时间:2015-11-15 09:39:45      阅读:434      评论:0      收藏:0      [点我收藏+]

标签:

This chapter briefly covers the main properties of the thread API. Each part will be explained

further in the subsequent chapters, as we know how to use the API. More details can be found

in various books and online sources. We should note that the subsequent chapters introduces

the concepts of locks and condition variables more slowly, with many examples; this chpater is

thus better used as a reference.

              Crux: How to Create and Control Threads

What interface should the OS present for thread creation and control ? How should these 

interfaces be designed to enable ease use of as well as utility?

                   Thread Creation

The first thing you have to be aboe to write a multi-threaded program is to create new threads,

and thus some kind of thread creation interface must exist. In POSIX, it is easy:

#include <pthread.h>
int pthread_create(pthread_t* thread, const pthread_attr_t* attr.
                            void* (*start_routine)(void*), void* arg);                            

This declaration might look a little complex (particularly if you haven‘t used function pointers in

C), but actually it‘s not too bad. There are four arguments: thread, attr, start_routines, and arg.

The first, thread, is a pointer to a structure of type pthread_t; we will use this structure to 

interact with this thread, and thus we need to pass it to pthread_create() in order to initialize it.

The second argument, attr, is used to specify any attributes this thread might have. Some

example include setting the stack size or perhaps information about the scheduling priority of

the thread. An attribute is initialized with a separate call to pthread_attr_init(); see the mannual

page for details. However, in most cases, the defaults will be fine; in this case, we will simply 

pass the value NULL in.

The third argument is the most complex, but is really just asking: which function should this

thread start running in? In C, we call this a function pointer, and this one tells us the following

is expected: a function name (start_routine), which is passed a single argument of type void*

(as indicated in the parenthese after start_routine), and which returns a valur of type void*.

If this routine instead required an integer argument, instead of a void pointer, the declaration

would look like this:

int pthread_create(...,
                           void* (*start_routine)(int),
                           int arg);
                               

If instead the routine took a void pointer as an argument, but returned an integer, it would look

look this:

int pthread_create(...,
                            int (*start_routine)(void*),
                            void* arg);

Finally, the fouth argument, arg, is exactly the argument to be passed to the function where

the thread begins execution. You might ask: why do we need these void pointers? Well, the

answer is quite simple: having a void pointer as an argument to the function start_routine allows

us to pass in any type of argument; having it as a return value allows the thread to return any

type of result.

Let‘s look at an example. Here we just create a thread that is passed two arguments, packaged

into a single type we define ourselves. The thread, once created, can simply cast its argument to

the type it expects and thus unpack the arguments as desired.

And there it is! Once you create a thread, you really ahve another live executing entity, complete

with its own call stack, running within the same address space as all the currently existing 

threads in the program. The fun thus begins!

#include <pthread.h>

typedef struct __myarg_t {
      int a;
      int b;
} myarg_t;

void* mythread(void* arg) {
      myarg_t* m = (myarg_t*)arg;
      printf("%d %d\n", m->a, m->b);
 
      return NULL;
}

int main(int argc, char* argv[]) {
     
      pthread_t p;
      int rc;
 
      myarg_t args;
      args.a = 10;
      args.b = 20;
      rc = pthread_create(&p, NULL, mythread, &arg);
      ......
}

                    Thread Completion

The example above shows how to create a thread. However, what happens if you want to wait

for a thread to complete? You need to do something special in order to wait for completion;

in particular, you must call the routine pthread_join(). 

 

int pthread_join(pthread_t thread, void** value_ptr);

 

This routine takses two arguments. The first is of type pthread_t, and is used to specify which

thread to wait for. This variable is initialized by the thread creation routine (when you pass a

pointer to it as an argument to pthread_create()); if you keep it around, you can use it to wait

for that thread to terminate.

The second argument is pointer to the return value you expect to get back. Because the routine

can return anything, it is defined to return a pointer to void; because the pthread_join() routine

changes the value of the passed in argument, you need to pass in a pointer to that value, not

just the value itself.

Let‘s look at another example. In the code, a single thread is again created, and passed a couple

of arguments via the myarg_t structure. To return values, the myret_t type is used. Once the

thread is finished running, the main thread, which has been waiting inside of the pthread_join()

routine, then returns, and we can access the values returned from the thread, namely is in

myarg_t.

Second, if we are just passing in a single value (e.g., an int), we don‘t have to package it up

as an argument. Figure 27.3 shows an example. In this case, life is a bit simpler, as we don not

have to package arguments and return values inside of functions.

Third, we should note that one has to be extremely careful with how values are returned from

a thread. In particular, never return a pointer which refers to something allocated on the thread‘s

call stack. If you do, what do you think will happen? (think about it!) Here is an example of a 

dangerous piece of code, modified from the exampe in Figure 27.2.

void* mythread(void* arg) {
     myarg_t*  m = (myarg_t*)arg;
     printf("%d %d\n", m->a, m->b);
     myret_t r;
     r.x = 1;
     r.y = 2;
     
     return (void*)&r;
}

THIS IS PLACEHOLDER.

Operating System: Three Easy Pieces --- Thread API (Note)

标签:

原文地址:http://www.cnblogs.com/miaoyong/p/4966134.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!