什么是线程?
“线程”有时候被称为轻量级进程,是程序执行流的最小单元,一个标准的线程由线程ID,当前指令指针(PC),寄存器集合和堆栈组成。另外,线程是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点在运行中必不可少的资源,但它可与同属一个进程的其它线程共享进程所拥有的全部资源。一个线程可以创建和撤消另一个线程,同一进程中的多个线程之间可以并发执行。由于线程之间的相互制约,致使线程在运行中呈现出间断性。每一个程序都至少有一个线程,那就是程序本身。线程是程序中一个单一的顺序控制流程。 在单个程序中同时运行多个线程完成不同的工作,称为多线程。由于同一进程的多个线程共享同一地址空间,因此Text Segment、Data Segment都是共享的,如果定义一个函数,在各线程中都可以调用,如果定义⼀个全局变量,在各线程中都可以访问到。
除此之外,各线程还共享以下进程资源和环境:
- ⽂件描述符表
- 每种信号的处理⽅式(SIG_IGN、SIG_DFL或者自定义的信号处理函数
- 当前共享内存
- ⽤户id和组id
但有些资源是每个线程各有⼀份的:
- 线程id
- 上下文,包括各种寄存器的值、程序计数器和栈指针
- 栈空间
- errno变量
- 信号屏蔽字
- 调度优先级
Linux下线程的特点:
1.线程的私有
2.独立调度和分配的基本单位
3.可并发执行
4.共享进程资源
线程与进程的区别:
(1)地址空间和其它资源(如打开文件):进程间相互独立,同一进程的各线程间共享。某进程内的线程在其它进程不可见。
(2)通信:进程间通信IPC,线程间可以直接读写进程数据段(如全局变量)来进行通信——需要进程同步和互斥手段的辅助,以保证数据的一致性。
(3)调度和切换:线程上下文切换比进程上下文切换要快得多。
(4)在多线程OS中,进程不是一个可执行的实体。
线程创建/等待/终止
创建
#include<stdio.h>
#include<stdlib.h>
#include<pthread.h>
void *thread_run(void *arg)
{
printf("new thread,thread is :%u,pid is:%d\n",pthread_self(),getpaid());
return (void *)1;
}
int main()
{
pthread_tid;
pthread_create(&tid,NULL,thread_run,NULL);
printf("main thread,thread is:%u,pid is:%d\n",pthread_self(),getpid());
return 0;
}
等待
#include<stdio.h>
#include<stdlib.h>
#include<pthread.h>
void *thread_run(void *arg)
{
printf("new thread,thread is :%u,pid is:%d\n",pthread_self(),getpaid());
return (void *)1;
}
int main()
{
pthread_tid;
pthread_create(&tid,NULL,thread_run,NULL);
void *ret;
pthread_join(tid,&ret);
printf("join new success,ret:%d\n",(int)ret);
return 0;
}
终止
(1)从线程函数内部return。注意:主线程退出,所有线程都会退出。
(2)一个线程可以调用pthread_cancel终止同一进程中的另一个线程。
(3)使用pthread_exit函数终止线程。
线程分离与结合属性
在任何一个时间点上,线程是可结合的(joinable),或者是分离的(detached)。一个可结合的线程能够被其他线程收回其资源和杀死;在被其他线程回收之前,它的存储器资源(如栈)是不释放的。相反,一个分离的线程是不能被其他线程回收或杀死的,它的存储器资源在它终止时由系统自动释放。 为了避免存储器泄漏,每个可结合线程都应该要么被显示地回收,即调用pthread_join;要么通过调用pthread_detach函数被分离。 由于调用pthread_join后,如果该线程没有运行结束,调用者会被阻塞。因此,我们就可以在子线程中加入pthread_detach(pthread_self())或者父线程调用pthread_detach(thread_id)(非阻塞,可立即返回)。这样将子线程的状态设置为分离的(detached),如此一来,该线程运行结束后会自动释放所有资源。