线程的相关基础知识
线程的概念
- 在一个程序里执行路线,一个程序内部的控制序列。
一切进程至少有一个线程
线程与进程
进程是资源竞争的基本单位
- 线程是进程执行的最小单位
- 线程被包括在进程之中
- 如果定义一个函数,在各线程中都可以调用,如果定义一个全局变量,在各线程中都可以访问到。
- 两者一般的关系为:单线程进程,单进程多线程,多线程单进程,多进程多线程(一般而言,多进程多线程不处理,因为会造成很多问题)
- 进程退出后,它的所有线程也会退出,一般情况下,只有线程退出后,进程才会退出。
线程的优缺点
优点
- 创建一个线程的代价比进程小很多。
- 线程之间的切换需要操作系统的工作要少很多
- 线程占用的资源比进程少很多
- 程序在等待慢速操作的同时,可执行其他的计算任务。
- 所有的线程都是对等关系
缺点
- 性能损失比较严重
- 健壮性降低
- 缺乏访问控制
- 编程的难度会提高
线程的控制
线程创建
#include<stdio.h>
#include<string.h>
#include<pthread.h>
#include<unistd.h>
#include<stdlib.h>
int main(void)
{
pthread_t tid;
int ret;
if((ret=pthread_create(&tid,NULL,rout,NULL))!=0)//创建一个线程,rout代表的是要执行的函数,成功返回0,失败返回-1
{
exit(EXIT_FAILURE);
}
int i;
for(; ;)
{
printf("main thread");
sleep(1);
}
//
@localhost 0802]$ ps -L
PID LWP TTY TIME CMD
31478 31478 pts/3 00:00:00 bash //LWP代表线程的ID,PID代表进程ID
31498 31498 pts/3 00:00:00 python //进程ID和主线程ID相同
31753 31753 pts/3 00:00:00 ps
//线程ID由gettid来获得,进程ID由getpid获得
- 线程的地址空间
- 线程的地址空间在进程内,而进程的创建在堆上。
线程等待
- 为什么要进行线程等待?
- 有很多时候,已经退出的线程,其空间没有被释放,仍然在进程的地址空间内;创建新的线程不会复制刚刚已经退出的线程,所以就需要线程等待。
- 成功返回0,失败返回错误码
int main(void)
{
pthread_t tid;
void * ret;
pthread_create(&tid,NULL,thread1,NULL);//thread1表示需要回调的函数
pthread_join(tid,&ret);//ret指向代表线程创建的返回值,该函数成功返回0。
printf("thread 1");
free(ret);//若成功,释放资源
pthread_create(&tid,NULL,thread2,NULL);//然后进行线程2
pthread_join(tid,&ret);
printf("thread 2");
}
线程终止
成功返回0,失败返回错误码
int main(void)
{
pthread_t tid;
void * ret;
pthread_create(&tid,NULL,thread1,NULL);
pthread_join(tid,&ret);//等待线程1结束之后,释放空间
printf("thread 1");
free(ret);
pthread_cancle(tid);//线程的终止
pthread_join(tid,&ret);
}
线程分离
- 默认的情况下,线程的状态都是joinable的,线程退出之后,需要对其进行线程终止操作,否则无法释放资源,会造成内存泄漏。
- 如果不关心线程的返回值,join是一种负担,这个时候,可以告诉系统,线程退出后自动释放资源,所以就出现了线程分离。
- 但是一个线程只能有joinable和分离两种状态中的一种。
int main(void)
{
pthread_t tid;
void * ret;
pthread_create(&tid,NULL,thread1,NULL);
pthread_join(tid,&ret);//等待线程1结束之后,释放空间
free(ret);
}
}
void *thread1(void *arg)
{
pthread_detach(pthread_self());//参数是自己
printf("%s\n",(char*)arg);
return NULL;
}