线程作用特点,为啥要有这个东西
- 轻量,大部分资源共享父线程,所以创建起来花费相比进程低
- 通信方便,因为堆的资源是共享的,所以子线程可以方便的通信
- 当父线程结束时,子线程就结束了,与进程不一样
- 一个进程可以有多个线程
- 不共享的资源:
- 线程id
- 信号掩码
- error变量
- 实时调度策略和优先级
- 栈、本地变量
创建线程
线程库不属于标准库所以编译链接的时候需要指定线程库 -pthread
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
// callback function
void* callback(void* arg) {
printf("child thread...\n");
printf("arg value: %d\n", *(int *)arg);
}
int main() {
pthread_t tid;
int num = 10;
// create a child thread
int ret = pthread_create(&tid, NULL, callback, (void *)&num);
if(ret != 0) {
char* errstr = strerror(ret);
printf("error: %s\n", errstr);
}
sleep(1); // what will happen, if delete this statement
return 0;
}
pthred_exit/pthread_self
void pthread_exit(void *retval)
- 功能: 终止一个线程,但是不会带走其子线程,
- 参数:一个指针用于接收子线程返回值,需要join
pthread_t pthread_self(void)
- 功能: 获取当前线程pid
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
// callback function
void* callback(void* arg) {
sleep(1);
printf("child thread...\n");
printf("arg value: %d\n", *(int *)arg);
pthread_exit(0); // return 0;
}
int main() {
pthread_t tid;
int num = 10;
// create a child thread
int ret = pthread_create(&tid, NULL, callback, (void *)&num);
if(ret != 0) {
char* errstr = strerror(ret);
printf("error: %s\n", errstr);
}
printf("tid: %ld, main thread id: %ld\n", tid, pthread_self());
// 终止一个线程
// 不会带走其子线程
pthread_exit(NULL);
printf("main thread exit\n");
return 0;
}
join
int pthread_join(pthread_t thread, void **retval);
- 功能: 和一个已经终止的线程进行连接,回收子线程的资源
- 特点: 阻塞函数,调用一次只能回收一个子线程
- 参数:
- thread: 需要回收的子线程的ID
- retval: 接收子线程退出的返回值
- 返回值
- 0: 成功
- 非0: 对应的错误号
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
void* callBack(void* num) {
puts("I'm child pthread");
printf("%d\n", *(int*)num);
printf("pthread_id: %ld\n", pthread_self());
// int* val = new int(10);
int val = 10;
return (void*) 10;
}
int main() {
int num = 10;
pthread_t* pid;
int ret = pthread_create(pid, NULL, callBack, (void*)&num);
if(ret != 0) {
puts(strerror(ret));
}
int* val;
if(ret != 0) {
puts(strerror(ret));
}
// 需要修改val指针的指向
pthread_join(*pid, (void**) &val);
printf("%d\n", *val);
}
detach
int pthread_detach(pthread_t thread)
- 功能: 分离一个线程。被分离的线程在终止时,会自动被释放资源返回给系统,
- 注意:不能多次分离,不能去连接一个分离的线程;分离的线程还是属于原进程,当main 结束return 时,也就是进程结束时,还是会带走该线程。怎么验证这一点呢?可以输出子线程的pid
- 参数: 需要分离的线程的ID
- 返回值:
- 0: 成功
- 非0: 错误号
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
// callback function
void* callback(void* arg) {
sleep(1);
printf("child thread...\n");
printf("my pid = %d\n", getpid());
printf("arg value: %d\n", *(int *)arg);
// 当main return时,如果不带走子线程,那么这个文件会被创建
int fd = open("/home/dyj/byMyself/basic/thread/in.txt", O_CREAT | O_RDWR, 0664);
if(fd == -1) {
perror("open");
}
write(fd, "123", 4);
close(fd);
}
int main() {
pthread_t tid;
int num = 10;
// create a child thread
int ret = pthread_create(&tid, NULL, callback, (void *)&num);
if(ret != 0) {
char* errstr = strerror(ret);
printf("error: %s\n", errstr);
}
pthread_detach(tid);
printf("%d\n",(int)getpid());
printf("%ld\n %ld\n", tid, pthread_self());
puts("father thread die");
// sleep(1);
pthread_exit(0);
return 0; // 有前一句,这句不会被执行
}
cancel
int pthread_cancel(pthread_t thread);
- 功能:
- 取消线程(让线程终止),不是立即取消,是到可取消点才能取消
- 如果取消的是main线程,同样不会立即回收资源,而是停止,等所有线程结束后,再回收资源
- 参数: 待取消点线程id
- 返回值:
puts("cancelled");
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
void* callBack(void* arg) {
for(int i = 0; i < 5; i++) {
printf("I'm pthread, My tid= %ld\n", pthread_self());
}
}
int main() {
pthread_t tid;
int ret = pthread_create(&tid, NULL, callBack, NULL);
if(ret != 0) {
puts(strerror(ret));
_exit(0);
}
if(ret != 0) {
puts(strerror(ret));
_exit(0);
}
ret = pthread_cancel(tid);
ret = pthread_cancel(pthread_self());
puts("cancelled");//有输出,说明不是立即取消
puts("cancelled");
puts("cancelled");
puts("cancelled");
puts("cancelled");
puts("cancelled");
for(int i = 0; i < 5; i++) {
printf("I'm man thread, My tid= %ld\n", pthread_self());
}
}
attr
体验设置线程的attr属性
#include <stdio.h>
#include <pthread.h>
#include <string.h>
#include <unistd.h>
void* callback(void* arg) {
puts("Im a pthread");
}
int main() {
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pthread_t tid;
int ret = pthread_create(&tid, &attr, callback, NULL);
if(ret != 0) {
puts(strerror(ret));
_exit(0);
}
size_t size;
pthread_attr_getstacksize(&attr, &size);
printf("thread stack size: %ld\n", size);
printf("tid: %ld, main thread id: %ld\n", tid, pthread_self());
pthread_attr_destroy(&attr);
pthread_exit(0);
}
问题
- 为什么需要join/detach线程,如果我不这样,有哪些资源是不可回收的或者释放的呢?子线程正常结束时,哪些资源是不能自己释放的?