线程与进程
进程是操作系统资源分配的基本单位,而线程是任务调度和执行的基本单位,线程在某种程度上可以看做轻量级的进程。
每个进程都有独立的代码和数据空间,程序间的切换会有较大开销;同一组线程可以共享代码和数据空间,每个线程仍具有自己独立的运行栈和程序计数器,程序之间切换的开销也较小。
由于线程共享进程地址空间的所有资源,所以线程之间的通信很方便;多个线程处理不同人物,增加了程序的并发性,是程序高效运行。
线程的创建
同进程一样,每个线程都有自己的ID,使用的数据类型为pthread_t,其本质也是一种无符号整型。Linux下使用pthread_t pthread_self(void)函数得到一个线程的ID,包含在头文件pthread.h中;进程的创建函数为int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(*start_rtn)(void *), void *restrict arg),第一个参数为指向存储创建进程的ID变量的指针。第二个参数表示线程属性,可置为NULL。第三个参数为一个函数指针,指向创建的线程的主体,即pthread_create()函数创建的线程从start_rtn所指向的函数的起始地址开始执行,当函数返回时该线程就停止运行了。如果线程创建成功了,函数返回0,若是失败则返回错误编号,因此需要对错误编号进行识别。
编写一个线程创建的例子:
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<pthread.h>
#include<string.h>
#include<errno.h>
void *thfn(void *arg){
pid_t pid;
pthread_t tid;
pid = getpid(); //获得本进程的进程ID
tid = pthread_self(); //获得本线程的线程ID
printf("the created thread: pid is %u, tid is %u \n", (unsigned int)pid, (unsigned int)tid); //打印获得的进程、线程ID
return NULL;
}
int main(){
pid_t pid;
int err; //声明错误编号变量
pthread_t mtid; //声明线程变量
pid = getpid();
mtid = pthread_self(); //获取主线程ID
printf("The main thread: pid is %u, tid is %u \n", (unsigned int)pid, (unsigned int)mtid);
err = pthread_create(&mtid, NULL, thfn, NULL);
if(err != 0){
printf("Can't create thread %s\n", strerror(err));
exit(1);
}
sleep(1);
printf("The created thread: pid is %u, tid is %u \n", (unsigned int)pid, (unsigned int)mtid);
mtid = pthread_self();
printf("The main thread: pid is %u, tid is %u \n", (unsigned int)pid, (unsigned int)mtid);
return 0;
}
因为pthread库不是Linux默认的库,所以链接时需要用到libpthread.a,在编译时加入-lpthread。编译和运行结果:
创建的新线程只执行thfn()函数,执行之后线程就退出了,在执行过程中可以访问进程资源。
线程的终止
线程的退出方式有:
- 线程函数执行结束,类似于进程中的main()函数返回(正常退出);
- 线程被另一个线程所取消,类似于进程中的kill(异常退出);
- 线程自行退出,类似于进程中调用exit()(异常退出);
Linux环境下使用pthread_cancel(pthread_t tid)函数取消一个线程,函数参数表示要取消的线程的ID,取消成功返回0,否则返回错误编号。