1. 基础概念
早期unix系统中,没有线程概念,后来才引入线程
linxu 为了迎合 windows引入了线程
gdb不支持线程,因为gdb比线程出现了早
区别:
线程: 有独立的pcb. 没有独立的进程地址空间,线程在进程内部,共享进程地址空间
进程: 有独立的进程 地址空间,有独立的pcb
线程是分配资源的最小单位,如何理解: * 如果一个进程A有3个线程,那么cpu会把A进程当作4个进程,cpu分配时间片个A进程 给优先
是不是线程越多进程优先级越高: 但线程数量达到一定程度的时候,优先级会降低
进程是分配资源的最小单位:
本章总结 线程进程函数总结对比
* pthread_create() fork()
* pthread_self() getpid()
* pthread_exit() exit()
* pthread_join() wait/waitpid
* pthread_cancle() kill
* pthread_detach()
2. 线程函数
2.1.pthread_create
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <signal.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <pthread.h>
#include <errno.h>
#include <string.h>
void* tfun(void* args){
int* j=(int *)args;
printf("son thread.... pid = %d ... %lu-args--%d \n",getpid(),pthread_self(),*j);
// printf("---%d---",*j);
return NULL;
}
int main0000014(){
/**
* 线程共享资源:
* 1. 文件描述符表
* 2. 当前工作目录
* 3. 用户ID 和组 ID
* 4. 内存地址空间(.text/.data/.bss/堆/共享库)[共享全局变量]
* 非共享:
*1. 线程id
*2. 栈
* 优点: 效率高
*/
// lwp 标识线程身份,cpu调度区分 线程id: 进程内部不同线程区分
pthread_t tid;
// 线程id,线程属性,回调函数,回调函数参数
// 打印主线程
printf("main thread..pid = %d ... pthread %lu \n",getpid(),pthread_self());
int j=1000;
int ret = pthread_create(&tid,NULL,tfun,&j); // 返回线程id
sleep(1);
if(ret == -1){
perror("pthread_create fail");
exit(-1);
}
// gcc single.c -o single.o -lpthread
return 0;
}
2.1.1线程传递问题
void* tfun(void* args){
int* j=(int *)args;
printf("son thread.... pid = %d ... %lu-args--%d \n",getpid(),pthread_self(),*j);
// printf("---%d---",*j);
return NULL;
}
/**
* 循环创建多个线程
*/
int main0000015() {
pthread_t tid;
int ret=0;
for (int i = 0; i < 10; i++) {
// 错误
/**
* son thread.... pid = 3521 ... 140422606616320-args--2
son thread.... pid = 3521 ... 140422589830912-args--5
son thread.... pid = 3521 ... 140422598223616-args--3
son thread.... pid = 3521 ... 140422615009024-args--1
son thread.... pid = 3521 ... 140422581438208-args--7
son thread.... pid = 3521 ... 140422564652800-args--7
son thread.... pid = 3521 ... 140422573045504-args--7
son thread.... pid = 3521 ... 140422556260096-args--8
son thread.... pid = 3521 ... 140422479345408-args--9
son thread.... pid = 3521 ... 140422470952704-args--10
出现重复数据,
为什么: for循环不断执行当,但i=5的时候在栈中,子线程回调才第一次执行,才切换成内核态取出i=5,实际的需要的是0
解决方法: 直接传递值
*/
ret= pthread_create(&tid, NULL, tfun, (void*) &i); // 返回线程id
if (ret !=0 ) {
perror("pthread_create fail");
exit(-1);
}
}
sleep(1);
return 0;
}
2.2.pthread_self
void* tfun1(void* args){
int j=(int )args;
printf("son thread...tfun1.... pid = %d ... %lu-args--%d \n",getpid(),pthread_self(),j);
// printf("---%d---",*j);
return NULL;
}
int main0000016() {
pthread_t tid;
int ret=0;
for (int i = 0; i < 10; i++) {
ret= pthread_create(&tid, NULL, tfun1, (void*) i); // 返回线程id
if (ret !=0 ) {
perror("pthread_create fail");
exit(-1);
}
}
sleep(1);
return 0;
}
2.3.pthred_exit
/**
* exit: 退出进程
* pthred_exit 退出线程
*/
void* tfun3(void* args){
int j=(int )args;
if(j==2){
// return NULL; // 返回到函数调用者那里去
pthread_exit(NULL);
}
printf("son thread...tfun1.... pid = %d ... %lu-args--%d \n",getpid(),pthread_self(),j);
// printf("---%d---",*j);
return NULL;
}
int main0000017() {
pthread_t tid;
int ret=0;
for (int i = 0; i < 10; i++) {
ret= pthread_create(&tid, NULL, tfun3, (void*) i); // 返回线程id
if (ret == -1) {
perror("pthread_create fail");
exit(-1);
}
}
sleep(1);
return 0;
}
2.4.pthread_join 阻塞回收子线程 相当有 wait
/**
* pthread_join 阻塞回收子线程 相当有 wait
*/
void* tfun4(void* args){
return (void*)1100;
}
int main0000018() {
pthread_t tid;
// 成功返回0
int ret= pthread_create(&tid, NULL, tfun4, NULL); // 返回线程id
if(ret !=0){
perror("pthread_create erro");
exit(-1);
}
int *retval;
// 参数类型void**
// 参数1 线程id 参数2 回调函数返回值 tfun4
ret = pthread_join(tid,(void**)&retval);
if(ret!=0){
perror("pthread_create erro");
exit(-1);
}
// 返回值类型 -- return (void*)1100;
printf("resutl---%d",retval);
return 0;
}
2.4.1 回收多个线程
void* tfun5(void* args){
return args;
}
int main0000019() {
pthread_t tid[10];
int ret=0;
for (int i = 0; i < 10; i++) {
ret= pthread_create(&(tid[i]), NULL, tfun5, (void*) i); // 返回线程id
if (ret == -1) {
perror("pthread_create fail");
exit(-1);
}
}
int *retval;
sleep(1);
for(int j=0;j<10;j++){
pthread_join(tid[j],(void**)&retval);
printf("-sleep---%d----%d\n",tid[j],retval);
}
return 0;
}
2.5.pthread_cancel
void* tfun11(void* args){
while(1){
int j=(int )args;
/**
* 调用pthread_cancel 以后如果子线程不进入系统调用比如
* 没有调用printf、sleep函数那么无法杀死子线程
* 如果没有上面函数,自己添加取消点:
* 调用: pthread_testcancel();
*/
// printf("son thread...tfun1.... pid = %d ... %lu-args--%d \n",getpid(),pthread_self(),j);
// sleep(1);
pthread_testcancel();
}
return NULL;
}
/**
* pthread_cancel 相当于kill
*/
int main0000020() {
pthread_t tid;
int ret=0;
ret= pthread_create(&tid, NULL, tfun11, (void*) 1999); // 返回线程id
if (ret !=0 ) {
perror("pthread_create fail");
exit(-1);
}
int *retval;
// 杀死线程
/**
* 调用pthread_cancel 以后如果
*/
pthread_cancel(tid);
// 如果线程被杀死了,返回-1
pthread_join(tid,&retval);
printf("return value----- %d",retval);
//sleep(10);
return 0;
}
2.5.pthread_detach
void* tfun12(void* args){
int j=(int )args;
printf("son thread...tfun1.... pid = %d ... %lu-args--%d \n",getpid(),pthread_self(),j);
sleep(1);
return NULL;
}
/***
* pthread_detach
*/
int main0000021() {
pthread_t tid;
int ret= pthread_create(&tid, NULL, tfun12, (void*) 1999); // 返回线程id
if (ret !=0 ) {
fprintf(stderr,"pthread_create fail--%s \n",strerror(ret));
exit(1);
}
printf("---%d\n",ret);
ret= pthread_detach(tid); //设置线pthread_join程分离,0表示成功
printf("---%d\n",ret);
// 分离开以后,线程执行完毕会被自动回收tid,没有了,后面pthread_join 来回收会出错
if(ret!=0){
fprintf(stderr,"pthread_detach fail--%s \n",strerror(ret));
exit(1);
}
sleep(3);
// 功能判断是否分离开,分离,已经回收返回-1
int ret3 = pthread_join(tid,NULL);
printf("---%d\n",ret3);
// #define EINVAL 22 /* Invalid argument */
if(ret3!=0){
// strerror 无效,没有内容????
printf("%s\n",strerror(ret3));
}
return 0;
}
2.6.线程属性设置
/***
* 线程属性设置
* 例子:通过线程属性设置线程自动detach
*/
int main() {
pthread_t pid;
pthread_attr_t attr,newattr;
// 获取线程属性
int ret = pthread_attr_init(&attr);
if(ret!=0){
printf("pthread_attr_init--%s",strerror(ret));
exit(1);
}
ret = pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED); // 设置线程分离属性
if(ret!=0){
printf("pthread_attr_init--%s",strerror(ret));
exit(1);
}
pthread_t tid;
ret = pthread_create(&tid,&attr,tfun12,NULL);
if(ret!=0){
printf("pthread_create--%s",strerror(ret));
exit(1);
}
printf("main ..... pid:%d,tid=%lu\n",getpid(),pthread_self());
// 获取线程属性
// pthread_attr_getdetachstate(&newattr,PTHREAD_CREATE_DETACHED);
ret = pthread_attr_destroy(&attr);
if(ret!=0){
printf("pthread_attr_destroy--%s",strerror(ret));
exit(1);
}
sleep(5);
// 验证设置是否有效,出错表示有效
printf("----pthread_join 1---%d",ret);
ret = pthread_join(tid,NULL);
printf("----pthread_join 2---%d",ret);
if(ret!=0){
printf("pthread_join--%s",strerror(ret));
exit(1);
}
return 0;
}