线程基础
线程的创建、退出、分离、汇合
创建线程使用pthread_create
代码示例
线程的退出
线程的汇合和分离
线程对共享资源(临界资源)的访问
线程同步
线程同步——mutex锁
线程同步——条件变量
线程同步——信号量
进程间通讯(IPC)信号量集
进程和程序
进程是资源分配的基本单位,而线程是执行的基本单位。
进程和线程的关系
一个进程中可以有多个线程,最少有一个线程(主线程)。线程共享进程的资源。每个线程有自己独有的属性,线程id(tid)、线程栈帧、线程自己的信号屏蔽字等。进程的切换和进程间的通讯,消耗资源非常大且效率低下。而线程共享进程的资源,线程的切换和线程间的通讯很灵活、消耗资源非常少、效率很高。
验证一个进程中有多个线程,需要获取到进程的pid和线程的tid,获取进程的pid使用getpid函数即可,而获取线程的tid则使用pthread_self函数
pthread_c.c
执行结果
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsISPrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdsATOfd3bkFGazxCMx8VesATMfhHLlN3XnxCMwEzX0xiRGZkRGZ0Xy9GbvNGLpZTY1EmMZVDUSFTU4VFRR9Fd4VGdsYTMfVmepNHLrJXYtJXZ0F2dvwVZnFWbp1zczV2YvJHctM3cv1Ce-cmbw5yM4YTNkNWOkNTZ2YjMyQGO5cjZzMmNhJjZkhzYzATZ48CXxMzLchDMxIDMy8CXn9Gbi9CXzV2Zh1WavwVbvNmLvR3YxUjL4M3Lc9CX6MHc0RHaiojIsJye.png)
return和exit的区别:
在线程函数中调用return只是线程执行函数的结束。代表了线程的结束。如果在线程函数中调用exit函数将会终止整个进程,那么进程中的所有线程都会终止。所以切记,一定不要在线程执行函数中调用exit等函数。
终止一个线程使用pthread_exit函数。
调用pthread_cancel函数将终止其它线程
线程创建后,线程退出的时候,线程的资源自动回收,不需要主线程等待,这样的线程称为分离线程。
线程的分离使用pthread_detach函数
线程创建以后,线程退出后需要其它线程来回收该线程的资源,这样的线程称为线程的汇合。
线程汇合使用pthread_join()函数。
pthread_e.c
线程创建完毕,进程中的所有线程都是异步的。
要保证线程函数的安全,那么线程函数必须是可重入的。如果线程函数是不可重入的,那么对临界资源的访问将造成程序的乱序。
pthread_t.c
多个线程对临界资源进行访问的时候,需要由异步变为同步。
POSIX线程中提供了三种方式来进行线程同步。
mutex锁
条件变量
信号量
pthread_mutex_init
pthread_mutex_lock
pthread_mutex_trylock
pthread_mutex_unlock
pthread_mutex_destroy
pthread_m.c
什么是条件变量?
线程间的同步有这样一种情况:线程A需要等待某个条件成立才会继续往下执行,如果条件不成立则阻塞等待,而线程B在执行过程中使得这个条件成立,然后唤醒线程A继续往下执行。那么这个条件就是条件变量。
pthread库中通过使用pthread_cond_t类型来表示条件变量类型。
对这种类型的操作包括以下:
pthread_cond_init(3)
int pthread_cond_signal(pthread_cond_t *cond);
int pthread_cond_wait(pthread_cond_t *cond,pthread_mutex_t *mutex);
int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime);
int pthread_cond_destroy(pthread_cond_t *cond);
使用条件变量完成一个生产者和消费者的问题。
p_c.c
对于多个资源的共享使用信号量。
想使用其中的一个资源的时候,首先判断是否有可用资源。如果有,是资源的可用数量减1.如果没有可用资源,线程等待其他线程释放资源。当线程释放资源的时候,资源可用数量加1.
信号量是一个类型 sem_t
关于信号量的操作,系统提供了以下函数
sem_init(3)
sem_destroy(3)
sem_post(3)
sem_wait(3)
int sem_trywait(sem_t *sem);
使用信号量完成生产者和消费者模型,不再使用链表,使用循环队列完成。
p_cq.c
信号量集就是有一个或多个信号量组成的集合。
如何使用信号量集实现进程间的通讯?
获取一个键值。
通过键值获取信号量集semid。
semget(2)
对信号量集中的某一个信号量进行pv操作
使用函数semop(2)
为信号量集中的某一个信号量设置初值。或者获取信号量的值。
控制信号量集中某一个信号量,需要使用到semctl(2)
使用进程间通讯模仿TCP通讯结果。
server.c
client.c