线程
1.是操作系统能够进行调度的最小单位
2.线程被包含在进程之中,是进程中的实际运作单位
3.一个线程指的是进程中一个单一顺序的控制流
4.一个进程可以并发多个线程,每个线程执行不同的任务
比如四个人在一个房子里打麻将,创建一个新进程就相当于是在开一个房间,而创建一个新线程是在原有的房间中增加一个人而已
线程的优点
1.创建一个新的线程的代价要比创建一个新进程的代价小得多
2.与进程之间的切换相比,线程之间的切换需要操作系统做的工作要少很多
3.线程占有的资源要比进程少
4.线程之间共享数据更容易(线程是在一个房间中,所以相互通信比较容易,而进程之间通话需要跑到另一个房间)
线程的缺点
1.编码/调试难度提高
因为线程之间谁先执行不确定,在一个是共享资源的问题
2.缺乏访问控制
一个线程崩溃,会导致整个进程都异常终止,一个线程中调用某些函数,会影响整个进程
进程与线程的区别
1.进程:进程(或者任务)是资源分配的基本单位
2.线程:线程(或者轻量级进程)是调度/执行的基本单位
3.线程运行在进程中
4.一个进程至少都有一个线程
进程与线程中函数的对比
为什么线程/进程数不是越多越好?
1.线程/进程数目达到一定程度时,就不会再提高程序的执行效率了
2.线程/进程数目过多可能会导致进程异常终止
3.线程/进程数目过多可能会导致线程安全问题(线程安全:多个线程竞争同一资源)
线程创建
pthread_create
功能:创建一个新的线程
头文件:#include<pthread.h>
原型:
int pthread_create( pthread_t *pthread,
const pthread_attr_t*attr,
void*(*start_routine)(void*),
void *arg )
参数说明:
thread:返回线程ID,此参数是一个输出型参数
(返回的是新创建的线程的ID)
attr:设置线程的属性,attr为NULL表示使用默认属性(一般设为NULL)
(设置的是新线程的属性)
start_routine:是个函数地址,线程启动后需要执行的函数
(这是一个函数指针,指向线程的入口函数)
arg:传给线程启动函数的参数
返回值:成功返回0,失败返回错误码
线程被创建后,并不能保证那个线程先执行,新创建的线程和调用线程的执行顺序不确定,由操作系统进行调度
示例
1.创建一个线程
代码:
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<pthread.h>
void*ThreadEntry(void*arg)
{
(void)arg;
printf("I am thread\n");
}
int main()
{
pthread_t tid;
int ret=0;
ret=pthread_create(&tid,NULL,ThreadEntry,NULL);
if(ret!=0)
{
perror("pthread_create");
exit(1);
}
printf("I am main\n");
sleep(1);
//让主线程睡眠1秒,是为了不让此线程跑的太快使整个进程结束
//如果主线程跑的太快,新创建的线程还没来的及执行,整个进程就已经结束了
return 0;
}
运行结果:
2.使用死循环来创建线程(死循环是为了防止主线程跑的太快,而使新创建的线程没有机会执行,让它循环多次相当于是等待新线程启动和执行)
代码:
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<pthread.h>
void*ThreadEntry(void*arg)
{
(void)arg;
while(1)
{
printf("I am thread,%1x\n",pthread_self());
sleep(1);
}
}
int main()
{
int ret=0;
pthread_t tid;
ret=pthread_create(&tid,NULL,ThreadEntry,NULL);
if(ret!=0)
{
perror("pthread_create");
exit(1);
}
while(1)
{
printf("I am main,%1x\n",pthread_self());
sleep(1);
}
return 0;
}
pthread_self()是得到当前线程的ID
线程创建函数在libpthread.so库中,所以在编译时需要将该库导入,命令如下:
例如编译create.c
gcc create.c -lpthread
就是说在编译时需要加上"-lpthread"
运行结果:
线程终止
如果需要终止某个线程,而不终止整个进程,有以下三种方法:
1.从需要终止的线程函数中
直接return
ps:这种方法对主线程不适用,因为从main函数return相当于调用exit,会使main函数直接退出
2.需要终止的线程可以调用pthread_exit()
来终止自己
3.一个线程可以调用pthread_cancel
来终止同一进程中的其他线程
pthread_exit()
1.功能:终止线程
2.原型:
void pthread_exit(void *value_ptr)
参数说明:
value_ptr:不要指向一个局部变量
3.返回值:
无返回值
pthread_cancel()
1.功能:取消一个执行中的线程
2.原型:
int pthread_cancel(pthread_t thread)
参数说明:
thread:需要取消的线程的ID
3.返回值:
成功返回0,失败返回错误码
1.直接return
#include<unistd.h>
#include<stdlib.h>
#include<stdio.h>
#include<pthread.h>
void*ThreadEntry(void*arg)
{
int count=0;
(void)arg;
while(1)
{
++count;
if(count>=5)
return NULL;
printf("I am thread,%1x\n",pthread_self());
sleep(1);
}
}
int main()
{
int ret=0;
pthread_t tid;
ret= pthread_create(&tid,NULL,ThreadEntry,NULL);
if(ret!=0)
{
perror("pthread_create");
exit(1);
}
while(1)
{
printf("I am main,%1x\n",pthread_self());
sleep(1);
}
return 0;
}
运行结果:
2.调用pthread_exit()
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<pthread.h>
void*ThreadEntry(void *arg)
{
int count=0;
(void)arg;
while(1)
{
++count;
if(count>=7)
pthread_exit(NULL);
printf("I am thread\n");
sleep(1);
}
}
int main()
{
int ret=0;
pthread_t tid;
ret=pthread_create(&tid,NULL,ThreadEntry,NULL);
if(ret!=0)
{
perror("ptherad_create");
exit(1);
}
while(1)
{
printf("I am main\n");
sleep(1);
}
return 0;
}
运行结果:
3.调用pthread_cancel()
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<pthread.h>
void *ThreadEntry(void*arg)
{
(void)arg;
while(1)
{
printf("I am thread\n");
sleep(1);
}
}
int main()
{
int ret=0;
int count=0;
pthread_t tid;
ret=pthread_create(&tid,NULL,ThreadEntry,NULL);
if(ret!=0)
{
perror("pthread_create");
exit(1);
}
while(1)
{
++count;
if(count>10)
pthread_cancel(tid);
printf("I am main\n");
sleep(1);
}
return 0;
}
运行结果:
pthread_exit
或者return
返回的指针所指向的内存单元必须是全局的或者是用manlloc分配的,不能在线程函数的栈上分配,因为当其它线程得到这个返回指针时线程函数就已经退出了
示例
1.return返回线程函数栈上分配的变量
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<pthread.h>
void*ThreadEntry(void*arg)
{
(void)arg;
int a=10;
int *p=&a;
printf("I am thread\n");
return (void*)p;
}
int main()
{
pthread_t tid;
void*ret;
int thread=0;
thread=pthread_create(&tid,NULL,ThreadEntry,NULL);
if(thread!=0)
{
perror("pthread_create");
exit(1);
}
printf("I am main\n");
pthread_join(tid,&ret);
printf("ret=%d\n",*(int*)ret);
return 0;
}
2.pthread_exit中的参数是线程函数在栈上分配的
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<pthread.h>
void*ThreadEntry(void*arg)
{
(void)arg;
int count=0;
int a=10;
int *p=&a;
while(1)
{
++count;
if(count>=5)
pthread_exit(p);
printf("I am thread\n");
sleep(1);
}
}
int main()
{
pthread_t tid;
void*ret;
int thread=0;
thread=pthread_create(&tid,NULL,ThreadEntry,NULL);
if(thread!=0)
{
perror("pthread_create");
exit(1);
}
printf("I am main\n");
pthread_join(tid,&ret);
printf("ret=%d\n",*(int*)ret);
return 0;
}
malloc分配
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<pthread.h>
void*ThreadEntry(void*arg)
{
(void)arg;
int count=0;
int *p=(int*)malloc(sizeof(int));
*p=10;
while(1)
{
++count;
if(count>=5)
pthread_exit(p);
printf("I am thread\n");
sleep(1);
}
}
int main()
{
pthread_t tid;
void*ret;
int thread=0;
thread=pthread_create(&tid,NULL,ThreadEntry,NULL);
if(thread!=0)
{
perror("pthread_create");
exit(1);
}
printf("I am main\n");
pthread_join(tid,&ret);
printf("ret=%d\n",*(int*)ret);
free(ret);//malloc后记得释放
return 0;
}
全局变量
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<pthread.h>
int a=20;
void*ThreadEntry(void*arg)
{
(void)arg;
int count=0;
int*p=&a;
while(1)
{
++count;
if(count>=5)
pthread_exit(p);
printf("I am thread\n");
sleep(1);
}
}
int main()
{
pthread_t tid;
void*ret;
int thread=0;
thread=pthread_create(&tid,NULL,ThreadEntry,NULL);
if(thread!=0)
{
perror("pthread_create");
exit(1);
}
printf("I am main\n");
pthread_join(tid,&ret);
printf("ret=%d\n",*(int*)ret);
return 0;
}