一. 进程与线程关系
进程: ./xxx --> 开启一个新的进程 进程是系统最小资源分配单位
int main() { --> 进程开始 …
return 0; --> 进程结束 }
线程: 一个进程内部的资源,是系统中调度的基本单位,所有子线程都是共有资源
二. 线程的函数接口 --> 封装在线程库 libpthread.so 头文件: pthread.h
库的路径: /usr/lib/i386-linux-gnu/libpthread.so
头文件的路径: /usr/include/pthread.h
三. 关于线程的函数接口
1. 创建一个新的线程 – pthread_create --> man 3 pthread_create
#include <pthread.h>
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);
//使用了该函数,就必须在编译时链接线程库 -lpthread Compile and link with -pthread.
例子: gcc create.c -o create -lpthread
thread: 新的线程的TID号
attr: 线程的属性;普通属性: NULL
start_routine: 线程的任务函数
arg: 主线程传递子线程的参数返回值: 成功:0 ,并且线程创建了 失败:错误码,并且线程没有创建
=================================================================
#include <stdio.h>
#include <pthread.h>
//子线程的任务函数
void *fun(void *arg)
{
int i;
printf("I am child thread!\n");
for(i=10;i>0;i--)
{
sleep(1);
printf("child i = %d\n",i);
}
}
int main()
{
pthread_t tid; //用于存放子进程的TID号
int ret;
//主线程
printf("I am main thread! before create!\n");
ret = pthread_create(&tid,NULL,fun,NULL);
if(ret != 0)
{
printf("pthread_create error!\n");
}
printf("I am main thread! after create!\n");
int i;
for(i=10;i>0;i--)
{
sleep(1);
printf("main thread i = %d\n",i);
}
return 0;
}
2. 接合线程 — 回收子线程的资源 — pthread_join() – man 3 pthread_join
#include <pthread.h>
int pthread_join(pthread_t thread, void **retval);
thread: 需要进行接合的子线程的TID号 retval: 存储子线程退出值的指针 如果填NULL,则不关注子线程的退出状态
返回值: 成功:0 失败:错误码
3. 线程的退出 — pthread_exit() — man 3 pthread_exit
#include <pthread.h>
void pthread_exit(void *retval);
retval: 子线程退出值 地址不能是局部变量
#include <stdio.h>
#include <pthread.h>
int exit_state = 5;
//子线程的任务函数
void *fun(void *arg)
{
printf("I am child thread!\n");
pthread_exit(&exit_state);
}
int main()
{
pthread_t tid; //用于存放子进程的TID号
int ret;
void *p = NULL;
//主线程
printf("I am main thread! before create!\n");
ret = pthread_create(&tid,NULL,fun,NULL);
if(ret != 0)
{
printf("pthread_create error!\n");
}
printf("I am main thread! after create!\n");
//阻塞地接合子线程
//pthread_join(tid,NULL);
pthread_join(tid,&p);
//p是指向退出值指针,只需要解引用p就可以,但是p是void* ,退出是int * ,需要强转类型才能正常解引用
printf("exit state = %d\n",*(int *)p);
return 0;
}
4. 线程属性 – 分离属性
分离: 主线程不需要调用pthread_join去接合子线程
非分离: 主线程需要调用pthread_join去接合子线程
4.1 属性变量 类型: pthread_attr_t
1) 定义一个属性变量pthread_attr_t attr;
2) 初始化属性变量 — pthread_attr_init — man 3 pthread_attr_init
#include <pthread.h>
int pthread_attr_init(pthread_attr_t *attr);
attr: 未初始化的属性变量的地址返回值: 成功: 0 失败: 非0错误码 pthread_attr_init(&attr);
3) 设置属性变量 — pthread_attr_setdetachstate – man 3
pthread_attr_setdetachstate#include <pthread.h> int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate); attr: 已经初始化过的属性变量 detachstate: 属性 PTHREAD_CREATE_DETACHED --> 分离属性 --> 不需要pthread_join PTHREAD_CREATE_JOINABLE --> 非分离属性 --> 需要pthread_join
4) 用这个属性变量创建的线程就是一个分离的线程
5) 销毁属性变量 — pthread_attr_destroy – man 3
pthread_attr_destroy#include <pthread.h> int pthread_attr_destroy(pthread_attr_t *attr); attr: 已经初始化过的属性变量 返回值: 成功: 0 失败: 非0错误码
分离属性的创建:
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
void *fun(void *arg)
{
printf("I am child thread!\n");
pthread_exit(NULL);
}
int main()
{
pthread_t tid;
//1. 定义一个属性变量
pthread_attr_t attr;
//2. 初始化属性变量
pthread_attr_init(&attr);
//3. 设置分离属性,主线程不关注子线程退出状态,子线程结束自动释放资源
pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);
//4. 创建一个新的子线程
pthread_create(&tid,&attr,fun,NULL);
//5. 销毁属性变量
pthread_attr_destroy(&attr);
pause();
return 0;
}
补充: 给线程设置分离属性 – pthread_detach()
//线程自己给自己设置一个分离属性 #include <pthread.h>
int pthread_detach(pthread_t thread);
thread: 需要设置分离属性的TID号
//获取自身的TID号
#include <pthread.h>pthread_t pthread_self(void);
返回值: 返回线程自身ID号
#include<stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/shm.h>
#include <semaphore.h>
#include <fcntl.h>
#include <sys/stat.h>
#include<stdlib.h>
void *fun(void *arg)
{
//给自己设置一个分离属性
pthread_detach(pthread_self());
//退出时自动释放资源
}
int main()
{
pthread_t tid;
pthread_create(&tid,NULL,fun,NULL);
pause();
}
5. 线程的取消 — pthread_cancel – man 3 pthread_cancel
#include <pthread.h>
int pthread_cancel(pthread_t thread);
thread: 线程的ID号
返回值: 成功: 0 失败: 错误码
#include <pthread.h>
#include <stdio.h>
void *fun(void *arg)
{
sleep(5);
printf("I am child thread!\n");
pthread_exit(NULL);
}
int main()
{
pthread_t tid;
pthread_create(&tid,NULL,fun,NULL);
sleep(1);
pthread_cancel(tid);
printf("I send cancel to child!\n");
pthread_join(tid,NULL);
return 0;
}
6. 设置线程的取消响应行为
1) 设置取消信号响应使能: 响应取消/不响应取消
线程创建后,默认是响应取消信号,立即响应信号
#include <pthread.h> int pthread_setcancelstate(int state, int *oldstate);
state: PTHREAD_CANCEL_ENABLE --> 使能取消
PTHREAD_CANCEL_DISABLE --> 不使能取消 oldstate: 原来的状态,不关注则填一个NULL2) 设置取消响应是立即取消,还是延迟取消!
int p取消thread_setcanceltype(int type, int *oldtype);
type: PTHREAD_CANCEL_DEFERRED 延后取消 PTHREAD_CANCEL_ASYNCHRONOUS 立即取消
延后取消: 遇到取消点才响应取消
取消点:为一个函数,运行完取消点函数后,子线程被取消,取消点规则详见https://linux.die.net/man/7/pthreads
#include <pthread.h>
#include <stdio.h>
void *fun(void *arg)
{
//pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED,NULL);//延后取消,即遇到取消点时取消,会运行取消点
//pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS,NULL); //立即取消
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,NULL); //不能取消
//sleep(5);
//printf("I am child thread!\n");
long long int i,j;
for(i=0;i<10000;i++)
{
for(j=0;j<1000000;j++)
{
//printf("I am child thread!\n");
}
}
while(1)
{
//fputc('h',stderr); //取消点(标准输出)
printf("I am child thread!\n");
}
pthread_exit(NULL);
}
int main()
{
pthread_t tid;
pthread_create(&tid,NULL,fun,NULL);
pthread_cancel(tid);
printf("I send cancel to child!\n");
pthread_join(tid,NULL);
return 0;
}