(1) 线程的概念
相信很多读者参加面试笔试的时候都被问及线程与进程的区别。我做概要分析如下
1> 进程是线程的载体,一个进程包含一个以上的线程,这些线程运行在进程的地址空间。
2> 进程是系统资源的分配拥有着,所有进程内的线程均可访问资源。
3> 线程是处理器调度的基本单位,但进程不是 。
4> 每一个进程都有一个主线程,其它线程均有主线程直接简介产生。
(2) 线程的控制
#include <pthread.h> int pthread_create(pthread_t *restrict thread, const pthread_attr_t *restrict attr, void *(*start_routine)(void*), void *restrict arg); void pthread_exit(void *value_ptr); //终止线程本身 int pthread_join(pthread_t thread, void **value_ptr); //其它线程获取线程的退出码
pthread_join 获取相关线程推出的返回值。它的值和线程的返回方式有关
return 一般执行完毕 获取return 返回值一般是数字
pthread_exit 自己推出 返回退出制定指针的值
pthread_cancel 其它线程异常终止 返回PTHREAD_CANCELED
(3)远堆传参
远堆传参,是指在堆中分配一块内存,又来作为线程启动的参数传递。如果是临时变量的话住线程创建玩子线程可能就会销毁临时变量。因为每个线程有各自的堆栈。所以子线程可能访问不到参数。这也是唯一不遵循内存分配原则的地方(谁分配谁释放)。主线程分配,子线程释放。 当然也可以使用全局变量。
(4)线程同步
线程共享同一进程内的资源,为了防止访问冲突,所以需要同步。同步机制。
1> 互斥锁 同一时刻只能一个线程访问该资源 即锁定
#include <pthread.h> int pthread_mutex_destroy(pthread_mutex_t *mutex); //销毁锁 int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);//初始化 int pthread_mutex_lock(pthread_mutex_t *mutex); int pthread_mutex_trylock(pthread_mutex_t *mutex); int pthread_mutex_unlock(pthread_mutex_t *mutex);
用pthread_mutex_init函数初始化的Mutex可以用pthread_mutex_destroy销毁。如果Mutex变量是静态分配的(全局变量或static变量),也可以用宏定义PTHREAD_MUTEX_INITIALIZER来初始化,相
当于用pthread_mutex_init初始化并且attr参数为NULL。pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
2> 信号量(Semaphore)
Mutex变量是非0即1的,可看作一种资源的可用数量,初始化时Mutex是1表示有一个可用资源,加锁时获得该资源,将Mutex减到0,表示不再有可用资源,解锁时释放该资源,将Mutex重新加到1,表示
又有了一个可用资源。 信号量(Semaphore)和Mutex类似,表示可用资源的数量,和Mutex不同的是这个数量可以大于1。不仅可用于同一进程的线程间同步,也可用于不同进程间的同步。
#include <semaphore.h> int sem_init(sem_t *sem, int pshared, unsigned int value); //初始化 int sem_wait(sem_t *sem); //等待 获取资源 int sem_trywait(sem_t *sem); //尝试等待 int sem_post(sem_t * sem); //释放 资源 int sem_destroy(sem_t * sem); //销毁
3> 条件变量 不太常用
#include <pthread.h> int pthread_cond_destroy(pthread_cond_t *cond); int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr); //pthread_cond_t cond = PTHREAD_COND_INITIALIZER; int pthread_cond_timedwait(pthread_cond_t *restrictcond, pthread_mutex_t *restrict mutex, const struct timespec *restrict abstime); int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex); int pthread_cond_broadcast(pthread_cond_t *cond); int pthread_cond_signal(pthread_cond_t *cond);
一个条件变量总是和一个互斥锁相关。所以使用起来比较繁琐,也不常用。下面是一个生产者和消费者的例子供学习参考。
#include <stdlib.h> #include <pthread.h> #include <stdio.h> struct msg { struct msg *next; int num; }; struct msg *head; pthread_cond_t has_product = PTHREAD_COND_INITIALIZER; pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; void *consumer(void *p) { struct msg *mp; for (;;) { pthread_mutex_lock(&lock); while (head == NULL) pthread_cond_wait(&has_product, &lock); mp = head; head = mp->next; pthread_mutex_unlock(&lock); printf("Consume %d ", mp->num); free(mp); sleep(rand() % 5); } } void *producer(void *p) { struct msg *mp; for (;;) { mp = malloc(sizeof(struct msg)); mp->num = rand() % 1000 + 1; printf("Produce %d ", mp->num); pthread_mutex_lock(&lock); mp->next = head; head = mp; pthread_mutex_unlock(&lock); pthread_cond_signal(&has_product); sleep(rand() % 5); } } int main(int argc, char *argv[]) { pthread_t pid, cid; srand(time(NULL)); pthread_create(&pid, NULL, producer, NULL); pthread_create(&cid, NULL, consumer, NULL); pthread_join(pid, NULL); pthread_join(cid, NULL); return 0; }
附加:pthread_detach
创建一个线程默认的状态是joinable, 如果一个线程运行结束但没有被join,则它的状态类似于进程中的Zombie Process(僵尸进程),即还有一部分资源没有被回收(退出状态码),所以创建线程者应该调用 pthread_join 来等待线程运行结束,并可得到线程的退出代码,回收其资源(类似于wait,waitpid)
但是调用pthread_join(pthread_id)后,如果该线程没有运行结束,调用者会被阻塞,在有些情况下我们并不希望如此
这时可以在子线程中加入代码
pthread_detach(pthread_self ())