Linux系统编程学习笔记_007_线程

目录

线程概念

线程控制原语

pthread_self函数

pthread_create函数

pthread_exit函数

pthread_join函数

pthread_cancel函数

pthread_detach函数

线程属性


线程概念

进程:独立地址空间,拥有PCB

线程:有独立PCB,但没有独立的地址空间(共享)

Linux下:线程是最小的执行单位,进程是最小的分配资源单位

ps -Lf 进程id  ——>线程号Lwp(CPU标识线程身份)

三级映射:进程PCB ——>页目录(首地址位于PCB)——> 页表 ——> 物理页面 ——> 内存单元

线程共享资源:

1. 文件描述符表

2. 每种信号的处理方式

3. 当前工作目录

4. 用户ID和组ID

5. 内存地址空间(.text .data .rodataa .bsss heap 共享库) 全局变量

线程非共享资源:

1. 线程id

2. 处理器现场和栈指针(内核栈)

3. 独立的栈空间

4. errno变量

5. 信号屏蔽字

6. 调度优先级

线程优缺点:

线程控制原语

pthread_self函数

获取线程ID,其作用对应进程中getpid()函数

原型:pthread_t pthread_self(void); 返回值:成功0 失败无

pthread_t为线程ID,在 Linux下为无符号整数,是进程内部识别线程的标志(两个进程间的线程ID允许相同)

pthread_create函数

原型:int pthread_create(pthread_t *tid, const pthread_attr_t *attr, void *(*start_rountn)(void *), void *arg); 创建子线程。

参1:传出参数,表新创建的子线程 id

参2:线程属性。传NULL表使用默认属性。

参3:子线程回调函数。创建成功,ptherad_create函数返回时,该函数会被自动调用。

参4:参3的参数。没有的话,传NULL

返回值:成功0 失败errno

示例代码,创建线程:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <pthread.h>
#include <fcntl.h>

void sys_err(const char *str){
	perror(str);
	exit(1);
}

void *tfn(void *arg){
	printf("thread: pid = %d, tid = %lu\n", getpid(), pthread_self());
	return NULL;
}

int main(int argc, char *argv[]){
	pthread_t tid; 
	printf("main: pid = %d, tid = %lu\n", getpid(), pthread_self());
	int ret = pthread_create(&tid, NULL, tfn, NULL);
	if(ret!=0){
		perror("pthread_create error");
	}
	sleep(1);	
	
	return 0; 
}

编译时需要在makefile中加上参数-lpthread,要注意在主线程执行完后地址会被销毁,因此要看到子线程的打印信息这里让主线程sleep一秒,结果如下:

示例,循环创建子线程,要注意传参使用值传递,借助强制类型转换(受参数类型限制):

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <pthread.h>
#include <fcntl.h>

void sys_err(const char *str){
	perror(str);
	exit(1);
}

void *tfn(void *arg){
	int i = (int) arg; 
	sleep(i);
	printf("I'm %dth thread: pid = %d, tid = %lu\n", i+1, getpid(), pthread_self());
	return NULL;
}

int main(int argc, char *argv[]){
	pthread_t tid; 
	int i,ret; 
	printf("main: pid = %d, tid = %lu\n", getpid(), pthread_self());
	for(i=0;i<5;i++){
		ret = pthread_create(&tid, NULL, tfn, (void*)i);
		if(ret!=0){
			sys_err("pthread_create error");
		}
	}
	sleep(i);		
	return 0; 
}

 结果如下:

pthread_exit函数

原型:void pthread_exit(void *retval);  退出当前线程。

exit(); 退出当前进程。

return: 返回到调用者那里去。

pthread_exit(): 退出当前线程。

主线程退出不影响子线程

pthread_join函数

原型: int pthread_join(pthread_t thread, void **retval); 阻塞回收线程。

参数thread: 待回收的线程id

返回值:传出参数。 回收的那个线程的退出值。

线程异常借助,值为 -1。

返回值:成功0 失败errno

示例代码,使用pthread_join函数回收子线程:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <pthread.h>
#include <fcntl.h>

struct thrd{
	int val;
	char str[256];
};

void sys_err(const char *str){
	perror(str);
	exit(1);
}

void *tfn(void *arg){
	struct thrd *tval;
	tval = malloc(sizeof(tval));
	tval->val = 100;
	strcpy(tval->str, "hello thread");
	return (void*)tval;
}

int main(int argc, char *argv[]){
	pthread_t tid; 
	struct thrd *retval;
	int ret = pthread_create(&tid, NULL, tfn, NULL);
	if(ret!=0){
		sys_err("pthread_create error");
	}
	ret = pthread_join(tid, (void **)&retval);
	if(ret!=0){
		sys_err("pthread_join error");
	}
	printf("child thread exit with var = %d, str = %s\n", retval->val, retval->str);
	pthread_exit(NULL);
}

结果如下:

pthread_cancel函数

原型:int pthread_cancel(pthread_t thread); 杀死一个线程。需要线程进入内核(取消点)有系统调用。

thread: 待杀死的线程id

返回值:成功0 失败errno

如果子线程没有到达取消点,那么pthread_cancel 无效。我们可以在程序中使用 pthread_testcancel(),手动添加一个取消点。

成功被 pthread_cancel() 杀死的线程,返回 -1.使用pthead_join 回收。

示例代码,使用pthread_cancel杀死线程:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <pthread.h>
#include <fcntl.h>

struct thrd{
	int val;
	char str[256];
};

void sys_err(const char *str){
	perror(str);
	exit(1);
}

void *tfn(void *arg){
	while(1){
		printf("thread: pid = %d, tid = %lu\n", getpid(), pthread_self());
		sleep(1); 
	}
	return NULL;
}

int main(int argc, char *argv[]){
	pthread_t tid; 
	int ret = pthread_create(&tid, NULL, tfn, NULL);
	if(ret!=0){
		fprintf(stderr, "pthread_create error:%s\n", strerror(ret));
		exit(1); 
	}
	
	printf("main: pid = %d, tid = %lu\n", getpid(), pthread_self());
	sleep(5);
	ret = pthread_cancel(tid);
	if(ret!=0){
		fprintf(stderr, "pthread_cancel error:%s\n", strerror(ret));
		exit(1);
	}
	while(1); 
}

结果如下:

 

pthread_detach函数

原型:int pthread_detach(pthread_t thread); 设置线程分离,网络,多线程服务器常用

参数thread: 待分离的线程id

返回值:成功0 失败errno 

示例代码,设置线程分离:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <pthread.h>
#include <fcntl.h>

void sys_err(const char *str){
	perror(str);
	exit(1);
}

void *tfn(void *arg){
	printf("thread: pid = %d, tid = %lu\n", getpid(), pthread_self());
	return NULL;
}

int main(int argc, char *argv[]){
	pthread_t tid; 
	int ret = pthread_create(&tid, NULL, tfn, NULL);
	if(ret!=0){
		fprintf(stderr, "pthread_create error:%s\n", strerror(ret));
		exit(1); 
	}
	ret = pthread_detach(tid); 
	if(ret!=0){
		fprintf(stderr, "pthread_detach error:%s\n", strerror(ret));
		exit(1);
	}
	ret = pthread_join(tid, NULL);
	if(ret!=0){
		fprintf(stderr, "pthread_join error:%s\n", strerror(ret)); 
	}
	printf("main: pid=%d, tid = %lu\n", getpid(), pthread_self());
	pthread_exit((void*)0);
}

结果如下,线程分离后,系统会自动回收资源,用pthread_join去回收已经被系统回收的线程,那个线程号就是无效参数。

线程进程控制原语对照:

 

线程属性

线程属性结构体中主要成员:

1. int etachstate 线程的分离状态

2. size_t stacksize 线程的栈大小(默认平均分配)

3. size_t guardsize 线程栈警戒缓冲区大小(位于栈末尾)

属性不能直接设置,需要使用相关函数

线程属性初始化

注:应先初始化线程属性,再pthread_create创建线程,pthread_create应放在下面两函数之间

int pthread_attr_init(pthread_attr_t *attr); 成功0 失败errno 初始化线程属性

int pthread_attr_destroy(pthread_attr_t *attr);成功0 失败errno 销毁线程属性缩占用的资源

线程分离状态的函数:

int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate); 设置线程属性 分离/非分离

int pthread_attr_getdetachstate(pthread_attr_t *attr, int *detachstate); 获取线程属性 分离/非分离

参数

attr:已初始化的线程属性  detachstate:  PTHREAD_CREATE_DETACHED分离线程PTHREAD_CREATE_JOINABLE 非分离

示例代码,创建分离态的线程:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <pthread.h>
#include <fcntl.h>

void sys_err(const char *str){
	perror(str);
	exit(1);
}

void *tfn(void *arg){
	printf("thread: pid = %d, tid = %lu\n", getpid(), pthread_self());
	return NULL;
}

int main(int argc, char *argv[]){
	pthread_attr_t attr; 
	pthread_t tid; 
	int ret = pthread_attr_init(&attr);
	if(ret!=0){
		fprintf(stderr, "pthread_create error:%s\n", strerror(ret));
		exit(1); 
	}
	ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 
	if(ret!=0){
		fprintf(stderr, "attr_set error:%s\n", strerror(ret));
		exit(1); 
	}
	ret = pthread_create(&tid, &attr, tfn, NULL);
	if(ret!=0){
		fprintf(stderr, "pthread_create error:%s\n", strerror(ret));
		exit(1); 
	}
	ret = pthread_join(tid, NULL); 
	if(ret!=0){
		fprintf(stderr, "pthread_join error:%s\n", strerror(ret));
		exit(1); 
	}
	printf("main: pid=%d, tid = %lu\n", getpid(), pthread_self());
	ret = pthread_attr_destroy(&attr);
	if(ret!=0){
		fprintf(stderr, "attr_destroy error:%s\n", strerror(ret)); 
		exit(1); 
	}

	pthread_exit((void*)0);
	
}

结果如下,说明分离的线程已经被系统回收

线程使用注意事项:

 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值