Multithreading 多线程
多线程的6个主要好处
- Programming abstraction
- Parallelism
- Improving responsiveness
- Blocking I/O
- Context switching
- Memory savings
Costs of Multithreading
不会用,用不好是最大的问题。
Alternatives to Multithreading
Threading Models
User-Level Threading
Hybrid Threading
Coroutines and Fibers
Threading Patterns
在创建一个多线程应用的时候最重要的就是决定线程模型。
Thread-per-Connection
Event-Driven Threading
Concurrency, Parallelism, and Races
Race Conditions
Pthread API
Creating Threads
#include <pthread.h>
int pthread_create (pthread_t *thread,
const pthread_attr_t *attr,
void *(*start_routine) (void *),
void *arg);
void *start_thread(void *arg);
pthread_t tread;
int ret;
ret = pthread_create (&thread, NULL, start_routine, NULL);
if (!ret) {
errno = ret;
perror("pthread_create");
return -1;
}
/* a new thread is created and running start_routine concurrently ... */
Thread IDs
线程可以通过pthread_self()函数在运行时获得它的TID:
#include <pthread.h>
pthread_t pthread_self (void);
用法很简单,因为函数不会失败:
const pthread_t me = pthread_self ();
Comparing thread IDs
#include <pthread.h>
int pthread_equal (pthread_t t1, pthread_t t2);
int ret;
ret = pthread_equal(thing1, thing2);
if (ret != 0)
printf("The TIDs are equal!\n");
else
printf("The TIDs are unequal!\n");
Terminating Threads
线程的终结有三种方式:
- 如果线程从start_routine返回,它将终止。这类似于main()的“从末尾结束”。
- 如果线程调用pthread_exit()函数,这类似于调用exit()。
- 如果线程通过pthread_cancel()函数被另一个线程取消,则它终止。这类似于通过kill()发送SIGKILL信号。
Terminating yourself
#include <pthread.h>
void pthread_exit (void *retval);
Terminating others
#include <pthread.h>
int pthread_cancel (pthread_t thread);
成功返回0,否则返回并设置errno
int ret;
/* `thread' is the thread ID of the to-terminate thread */
ret = pthread_cancel (thread);
if (ret) {
errno = ret;
perror ("pthread_cancel");
return -1;
}
int unused;
int ret;
ret = pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, &unused);
if (ret) {
errno = ret;
perror ("pthread_setcancelstate");
return -1;
}
ret = pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, &unused);
if (ret) {
errno = ret;
perror ("pthread_setcanceltype");
return -1;
}
Joinging and Detaching Threads
Joining threads
Joining允许一个线程在等待另一个线程终止时阻塞
#include <pthread.h>
int pthread_join(pthread_t thread, void **retval);
调用成功后,调用线程就会被阻塞,直到线程指定的线程终止为止(如果线程已经终止,那么就会直接返回)。
int ret;
/* join with `thread' and we don't care about its return value */
ret = pthread_join (thread, NULL);
if (ret) {
errno = ret;
perror ("pthread_join");
return -1;
}
Detaching threads
#include <pthread.h>
int pthread_detach (pthread_t thread);
A Threading Example
#include <stdio.h>
#include <pthread.h>
void * start_thread (void *message) {
printf ("%s\n", (const char *) message);
return message;
}
int main (void) {
pthread_t thing1, thing2;
const char *message1 = "Thing 1";
const char *message2 = "Thing 2";
/* Create two threads, each with a different message. */
pthread_create (&thing1, NULL, start_thread, (void *) message1);
pthread_create (&thing2, NULL, start_thread, (void *) message2);
/*
* Wait for the threads to exit. If we didn't join here,
* we'd risk terminating this main thread before the
* other two threads finished.
*/
pthread_join (thing1, NULL);
pthread_join (thing2, NULL);
return 0;
}
Pthread Mutexes
class ScopedMutex {
public:
ScopedMutex (pthread_mutex_t& mutex) :mutex_ (mutex) {
pthread_mutex_lock (&mutex_);
}
~ScopedMutex ()
{
pthread_mutex_unlock (&mutex_);
}
private:
pthread_mutex_t& mutex_;
};
//only one customer can withdraw
money at a time
static pthread_mutex_t the_mutex = PTHREAD_MUTEX_INITIALIZER;
int withdraw (struct account *account, int amount) {
pthread_mutex_lock (&the_mutex);
const int balance = account->balance;
if (balance < amount) {
pthread_mutex_unlock (&the_mutex);
return -1;
}
account->balance = balance - amount;
pthread_mutex_unlock (&the_mutex);
disburse_money (amount);
return 0;
}
// we allow the bank to process other customers’ withdraws in parallel.
//define the lock in account struct
int withdraw (struct account *account, int amount) {
pthread_mutex_lock (&account->mutex);
const int balance = account->balance;
if (balance < amount) {
pthread_mutex_unlock (&account->mutex);
return -1;
}
account->balance = balance - amount;
pthread_mutex_unlock (&account->mutex);
disburse_money (amount);
return 0;
}