Alright ima start with the lecture * Peradox sets mode: -m * Peradox sets mode: +m lol * nnp has joined #lecture OK, first of let me make this clear. This is not a beginner lecture; in fact you would probably need a degree in computing to understand this. I’m KIDDING. You don’t need anything special, however this is not a “learn C” lecture, but it delves into the more advanced topic of Threading. If you know the following you should probably stick around, as you have a lot to gain from POSIX threads. Here’s what I expect you know: hey nnp The C Language Spec and ANSI GLIBC Dynamic Memory Allocation / void * data types Function Pointers * D-TOX has joined #lecture * D-TOX has left #lecture If you don’t know this stuff, you can stick around and learn as well, I’m just saying this lecture was made for people who know. You can find a great tutorial on function pointers here (http://www.newty.de/fpt/index.html) and the other two topics can be found in any beginner C book. * D-TOX has joined #lecture Now, I’m going to do this the unconventional way and start with a little Q&A session right away. Does anyone not know what threads are, what POSIX is or so? Anyone want to know any background info? * Peradox sets mode: -m Qs? I'm back OK, guess not then hey char it started already :O hey * Cool_Fire has joined #lecture * Peradox sets mode: +m go on By the way, the examples in this text were tested only on Mac OSX, but I would be VERY surprised if they didn’t work on a different POSIX system. Also note that this lecture gives a cumulative overview of POSIX Threads, but in no means covers the whole API. I have purposely left out some non-portable or implementation specific code and functions. Now, with the POSIX model, a thread is a separate process, which shares the same memory space as the parent. For us mere mortals that means: A process doesn’t just COPY the free store and stack of the parent process (_main thread) but it makes pointers to it, so that if you modify a variable in a thread, this modifies the variable for all other threads as well. This can lead to serious bugs and security problems, if the programmer forgets to set MUTEXes and semaphores to circumvent this, When using POSIX threads (pthreads, or simply threads from now on) you need to always include and compile with the –lpthread option. I’m assuming you use CC or GCC. * D31337 has joined #lecture Threads are implemented as functions, meaning you write a function (of prototype void *thread_func(void *)) and then you can either just call it normally under the _main thread, or you can call it as a new thread. To call a function you must first initialize a couple of variables and then call pthread_create() passing those variables and the address of the thread function. Linux (or BSD, or whatever POSIX compliant or POSIX wrapped system you’re using) makes a new process with the same memory space as the _main process. Now you can also of course call threads from within threads… Let me present the most basic thread program #include #include void *pxs(void * unused) { while(1) puts(“x”); return NULL; } int main() { pthread_t thread; pthread_create(&thread, NULL, &pxs, NULL); while(1) puts(“o”); return 0; } if you compiled and ran the program you would get a seemingly endless stream of Xs’ and Os’ printed to stdout. Notice that the stream would be completely random, as Linux in no way guarantees synchronized scheduling. This may look like an obstacle, but is really perfectly reasonable, because, after all a thread is just another process, the one that has more to do goes first. If you need to have synchronized scheduling as a way to avoid race conditions, wait until we get to MUTEXes for a more elegant solution. Now let me explain the previous program: First I include pthread.h for threads and stdio.h for obvious reasons… Then I defined my thread function, which just prints a continuous stream of X’ to stdout. Note the prototype of this function, as all thread functions MUST affirm to this standard. Remember that void * pointer can be casted to any other pointer/address type so this should not be a problem. Now in main() I create a pthread_t variable, which is a thread handle, you will need a separate thread handle for each thread, unless you want to cause problems. Now we get to pthread_create(), the heart of this little program. Notice that two of the arguments are NULL, don’t worry about these right now. What’s important is that I passed the ADDRESS of the function pxs and the ADDRESS of the pthread_t variable thread. This calls the pxs function as a thread, and then continues to print a continuous stream of Os’ to stdout. This results in the unpredictable (well, actually it IS predictable, but that is out of the scope of this lecture, as we deal with pthreads, and not the Linux kernel) stream of X’s and O’s. Questions? * Peradox sets mode: -m lemme read :P lol ok give me a sec to catch up ;) anyone else think I should go slower? just a bit a tiny bit, yes yep * Peradox glances at scarlett johansson ok tell me when... btw, is anyone logging this? i probably am not me I can log it ;) cool ready? yeah ok go for it * Peradox sets mode: +m Now that you’ve learned how to create basic threads, I’ll spend the rest of the lecture fully introducing the pthread API. First off, almost all functions need some sort of parameter or argument to operate functionally, and obviously pthreads have to support this feature. To pass arguments you must first wrap your arguments in a void * pointer, which then in turn will be passed to the function by pthread_create(). If you want to pass more than one argument you must first put it in a struct. This is not as much work as it looks like; if I want to pass a char and an int to a function, I would: 1 Define the struct arg as struct arg { int i; char c; } 2. Now I can declare my arg structure and set the fields to the appropriate values. 3. I simply pass the address of the arg structure to pthread_create() as the fourth (final) parameter. most C compilers will automatically cast to void * here pthread_create() then passes this structure to your thread function * Cool_Fire has left #lecture which must in turn cast it back to the original datatype If I only want to pass one variable, I can simply just pass the argument to pthread_create() without wrapping it in a struct. I do NOT recommend doing this, always wrap your thread parameters. Here’s a snippet for you enjoyment: struct argument { int integer; char character; float decimal; } arg; pthread_create(&threaded, NULL, &thread_func, &arg); where threaded is the thread handle (of type pthread_t) and threadfunc is the thread function (of prototype void *(void *)). Questions? * Peradox sets mode: -m could you post the header of that function? the what? the prototype? sorry, the prototype aye btw, turns out i am logging this pthread_create(pthread_t *, pthread_attr_t *, void *(func)(void *), void *) i don't know the return value but i'm pretty sure its int anything else? OK no, thanks * Peradox sets mode: +m Now, as with all programs you should ask questions, about everything. What if the _main thread finishes executing before one of the other threads it’s spawned terminates? You create a “zombie thread” which can lead to problems. The solution is to have a function such as wait() (http://www.opengroup.org/onlinepubs/007908799/xsh/wait.html) except for threads. This function is called pthread_join(), it waits for a fellow thread until it terminates and then continues thread execution. So to wait until a another thread terminates before terminating the current thread, call pthread_join() from the thread passing the handle of the thread to wait on as the fist argument, and the void * pointer to the memory in which the threads return value should be stored in. If you do not want to store the thread’s return value pass NULL. as the second argument Sometimes you need to set a thread’s behavior more precisely, i.e. “customize it”, thread attributes allow you to do this. To create a thread attribute you must first create a pthread_attr_t object, and then call pthread_attr_init on it, passing its address as the parameter. Ex pthread_attr_t attr; pthread_attr_init(&attr); and when your done with it call pthread_attr_destroy() on it ( pthread_attr_destroy(&attr)); in between you can then pass it to a pthread attribute function, which will set that attribute on it. I’m not going to describe all the functions you can use on pthread_attr_t s, as you can find them all here: http://www.opengroup.org/onlinepubs/007908799/xsh/pthread.h.html Questions? * Ch4r sets mode: -m sorry :P ;) *reads* alright, ima go on... can you execute some commands in the main thread after calling the new thread and then call pthread_join() ? yes of course cheers you can use it just like fork() and wait() * Peradox sets mode: +m With child processes the parent can send the child an Interrupt (Ctrl-C) signal causing the process to terminate. Threads can also do this to each other by using the pthread_cancel() function, passing the thread id of the thread to be cancelled. Cancelled threads should then be joined to the calling thread. Now with the process model you can ignore an interrupt signal, and you can with threads as well. Say your thread has a critical section which must be done all or nothing, for example a malloc() and free() block, you can make your thread non-cancelable at certain points like that (asynchronous); err *synchronous if your thread can be cancelled at any time you can make asynchronous. You set these types by calling pthread_setcanceltype() from within the thread. pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); lets other threads cancel the thread whenever they want by calling pthread_cancel(). If you want to make your thread synchronously cancelable you need a little more effort; consider this thread function: void *func(void *arg) { pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL); pthread_testcancel(); char *new = (char *)malloc(128); /* … */ free(new); pthread_testcancel(); return NULL; } this thread can only be cancelled at the points where it calls pthread_testcancel(). So if the thread receives a cancel request from another thread, it will wait until the next pthread_testcancel() call to exit. There is one more cancellation type: un-cancelable. A thread may disable cancellation of itself completely by calling pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL). Thread cancellation can be re-enabled by calling pthread_setcancelstate(PTHREAD_CANEL_ENABLE, NULL). Questions * Peradox sets mode: -m ? nope ok * Peradox sets mode: +m MUTEXes are used to provide a point of mutual exclusion, i.e. to make sure no two threads access the same variables or data at the same time and/or create a race condition. If one thread locks a MUTEX, and then another thread tries to lock the MUTEX that thread blocks until the first thread unlocks the MUTEX. For example, what if you had a program that does operations on an integer taken you of an array. You decided that for efficiency you would use threads to compute each element of the array; a global integer n holds the value of the current element, i.e., the index of array[] so that each new thread takes that value at array[n] and then increments n. This sounds like a good plan, but, because of the scheduling of Linux’s threads a race condition can occur, i.e. one thread can get it’s variable, but before the thread has a chance to increment n, the next thread already gets its variable. MUTEXes avoid this. If each thread locks the MUTEX before getting its variable, and only unlocks it after it incremented n, each other thread would hold until the MUTEX became unlocked. To create a MUTEX you need to create a global (yes, global) pthread_mutex_t variable. This variable must then be initialized which can be done either with pthread_mutex_init(), or more simply by just assigning the special MACRO PTHREAD_MUTEX_INITIALIZER. (on Mac OS X using the latter causes a parse error) (don't ask me why) To lock a MUTEX call pthread_mutex_lock() passing the address of the pthread_mutex_t variable, and to unlock call pthread_mutex_unlock() with the same argument. ex: int data; pthread_mutex_t mutex ; pthread_mutex_lock(&mutex); data = array[n]; n++; pthread_mutex_unlock(&mutex); ... Beware that if you try to lock the same MUTEX twice in a row you will create a deadlock, as the MUTEX will never get unlocked since your thread locked it in the first place and is now holding until it gets unlocked. Occasionally it’s useful to check whether a MUTEX is locked without actually blocking, so that if it’s locked you can do some other work first and then try again. This is done with pthread_mutex_trylock(); if the MUTEX is unlocked you will lock it, and if it is already locked the error code EBUSY will be returned. * Peradox sets mode: -m Any questions about MUTEXes? ... that's a big NEGATIVE!!! * Anarkyst_blu is hyper lol no ok * Peradox sets mode: +m This lecture served as an introduction to adding threading to your Unix applications, I did not introduce everything there is to know about threads, and I did not intend too. I did not cover the following subjects and you should probably learn them on your own if you’re interested in using POSIX threads: Semaphores Handling signals with threads Debugging threads The wonderful Linux-specific threads functions Detached threads TSD (thread specific data) There’s more… That’s it for my lecture, if you want to learn more about pthreads, here are some tutorial links http://dis.cs.umass.edu/~wagner/threads_html/tutorial.html http://math.arizona.edu/~swig/documentation/pthreads/ http://www.llnl.gov/computing/tutorials/pthreads/ http://www.yolinux.com/TUTORIALS/LinuxTutorialPosixThreads.html http://users.actcom.co.il/~choo/lupg/tutorials/multi-thread/multi-thread.html http://www.reference.com/Dir/Computers/Programming/Threads/ http://www.humanfactor.com/pthreads/pthread-tutorials.html * Peradox sets mode: -m excellent! aight guys i like the llnl.gov one yeah, great lecture ' cool *reading*( hehe qwertydawom, send me logs? oh, there was a lecture? shit, i missed it lmao rofl Peradox, d'you mind if I put this on BU's site? not at all ok, thanks ch4r, i'll post it if ya want... nvm i dont have the full thing ok nnp are you the silentcode guy? aye awesome, your site is the shit although i don't go there much tis actually r4d30ns site w/e still all props to him for pretty much everything ok ok one thing, can you cancel other threads belonging to other processes? no heh thought as much