Linux 多线程
来源:互联网 发布:个人职业规划 知乎 编辑:程序博客网 时间:2024/06/05 01:10
目录:
- 线程种类
- 线程的创建
- 对线程的管理
- 线程的属性
- 线程之间的互斥
1、线程种类
– 内核态线程
(1)由内核调度程序直接调度,充分发挥多处理器的优势
(2)目前linux系统标准线程库采用内核线程方式实现多线程
– 用户态线程
(1)一个进程包含多个线程,这些线程从内核调度角度来看只是一个进程,内核把它当一个进程来调度。线程之间调度在用户态进行
(2)用户态线程优点是调度效率高(不需要内核参与调度),缺点是对于多核处理器利用率不高,一个线程阻塞会导致整个线程组阻塞
– 区分内核态线程与用户态线程
如果CPU为4核心,此时内核态线程有4个,那么CPU的4个核心分别执行一个线程,CPU的利用率最高,执行效率也最快,但是开始运行的时候线程会从用户态切换到内核态,运行完成线程后又从从内核态切换到用户态,这会消耗其他的资源,浪费时间。
如果此时用户态线程有4个,运行时操作系统只会给这个进程分配一个CPU核心数(进程是资源分配的最小单位),此时进程内的4个线程共用这一个CPU核心数,在进程内它们根据优先级的大小来轮流抢占这个进程的时间片实现“同步”,微观上讲是有间隔的,内核线程才是真正的同步,每个线程都运行在自己的CPU核心上,不用抢占时间片。由于用户态线程是运行在进程内部的,所以操作系统是不知道用户态线程的,它只知道这一个进程(这与线程是CPU调度的最小单位不矛盾)。
2、线程的创建
pthread_create
– #include<pthread.h>– int pthread_create(pthread_t *id, pthread_attr_t *attr, void *pFun, void *args)
• id : 返回线程ID
• attr: 线程属性,无属性设置填NULL
• pFun: 线程调用的函数
• args: 线程函数的参数
Demo
#include <stdio.h>#include <pthread.h>#include <stdlib.h>#include <unistd.h>#include <string.h>void* ThreadFunc(void* param){ int n = *((int*)param); int iRet = 0; int i; for (i = 0; i < n; i++) { iRet += i; fprintf(stderr, "thread[%d]->%d\n", n, iRet); usleep(100); } printf("\n"); return NULL;}int main(){ pthread_t thread_id; int num = 5; pthread_create(&thread_id, NULL, ThreadFunc, (void*)&num); pthread_join(thread_id, NULL); return 0;}
3、对线程的管理
Function
pthread_self()
功能:线程函数里,获取本线程的线程ID
int pthread_join(pthread_t id, void **pRet)
功能:使主进程等待线程完成后才退出
pRet: 获得 pthread_exit 函数调用的返回值
pthread_exit(void *pRet)
pRet:指定线程退出返回值
Demo
#include <stdio.h>#include <pthread.h>#include <stdlib.h>#include <unistd.h>#include <string.h>int g_pRet;void* thread(){ g_pRet = 100; pthread_exit(&g_pRet); return NULL;}int main(){ pthread_t tId; int iRet; iRet = pthread_create(&tId, NULL, thread, NULL); if (iRet) { perror("Fail to pthread_create!"); return iRet; } int *pRet; pthread_join(tId, (void*)&pRet); printf("thread exit code:pRet = %d\n", *pRet); return 0;}
4、线程的属性
线程属性结构体
struct pthread_attr_t { int __detachstate; int __schedpolicy; struct sched_param __schedparam; int __inheritsched; int __scope; size_t __guardsize; int __stackaddr_set; void * __stackaddr; unsigned long int __stacksize;
__detachstate:可分离属性(是否与进程中其他线程脱离同步)
__schedpolicy:调度策略
__schedparam:线程优先级
__inheritsched:继承属性
__scope:线程种类(内核态、用户态)
__guardsize:警戒缓冲区,防止桟溢出的扩展内存大小(防止一定程度的缓冲区溢出造成的程序崩溃)
__stackaddr_set:
__stackaddr:堆栈地址
__stacksize:堆栈的大小
Function
pthread_getattr_np(pthread_t id, pthread_attr_t *attr)
功能:获取线程属性
pthread_attr_init(pthread_attr_t *attr)
功能:初始化线程属性(初始化的为默认属性)
int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate)int pthread_attr_getdetachstate(pthread_attr_t *attr, int *pdetachstate)
功能:设置/获取线程分离状态
• PTHREAD_CREATE_JOINABLE 线程可与其他线程同步(默认),此时pthread_join()才会生效
• PTHREAD_CREATE_DETACHED 线程的资源在退出后自行释放
Demo
#define _GNU_SOURCE#include <stdio.h>#include <pthread.h>#include <stdlib.h>#include <unistd.h>void* ThreadFunc(void* param){ pthread_attr_t attr; // 线程函数里,获取本线程的线程ID pthread_t thread_id = pthread_self(); // 获取线程属性放在attr中 pthread_getattr_np(thread_id, &attr); int iDetachstate; // 从attr中获取detach属性 pthread_attr_getdetachstate(&attr, &iDetachstate); printf("detachstate:%s\n", PTHREAD_CREATE_JOINABLE==iDetachstate?"Joinble":"Detached"); return NULL;}int main(){ //Demo_ThreadAttr(); pthread_attr_t attr; // 初始化线程属性,初始化的为默认值,只有设置才能改变 pthread_attr_init(&attr); // 设置线程分离状态 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); pthread_t thread_id; pthread_create(&thread_id, &attr, (void*)ThreadFunc, NULL); usleep(1000); return 0;}
其他属性
int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy)int pthread_attr_getschedpolicy (pthread_attr_t *attr, int *pPolicy)
功能:设置/获取线程调度策略
• SCHED_OTHER 系统默认(分时调度),各个优先级任务时间轮换
• SCHED_FIFO 实时调度,先到先服务(独占)
• SCHED_RR 实时调度,时间片轮转(高优先级轮换)
int pthread_attr_setinheritsched(pthread_attr_t *attr, int inheritsched)int pthread_attr_getinheritsched(pthread_attr_t *attr, int *pinheritsched)
功能:设置/获取线程继承性
• PTHREAD_INHERIT_SCHED 从父进程继承调度属性
• PTHREAD_EXPLICIT_SCHED 不从父进程继承调度属性
int pthread_attr_setscope(pthread_attr_t *attr, int scope)int pthread_attr_getscope(pthread_attr_t *attr, int *pscope)
功能:设置/获取线程作用域
• PTHREAD_SCOPE_SYSTEM 系统所有进程间调度
• PTHREAD_SCOPE_PROCESS 当前进程间调度
int pthread_attr_setstackaddr(pthread_attr_t *attr, void * stackaddr)int pthread_attr_getstackaddr(pthread_attr_t *attr, void ** stackaddr)int pthread_attr_setstacksize(pthread_attr_t *attr, size_t *stacksize)int pthread_attr_setstacksize(pthread_attr_t *attr, size_t *stacksize)
功能:获取/设置线程桟信息
int pthread_attr_getguardsize(pthread_attr_t *attr, size_t *guardsize)int pthread_attr_setguardsize(pthread_attr_t *attr, size_t *guardsize)
功能:设置/获取线程警戒缓冲区
pthread_attr_destroy(pthread_attr_t *attr)
功能:无效化线程属性,无效化后, 使用attr 创建线程会失败
5、线程之间的互斥
多线程共享进程资源,访问共享资源时,需要进行互斥操作确保数据的有效性。此处讲解的为互斥锁实现线程的同步互斥。
互斥锁类型
– mutex 锁类型->PTHREAD_MUTEX_XXX
NORMAL: 普通锁,不提供死锁检测,可能出现死锁
ERRORCHECK: 检错锁,同一线程对已锁的互斥锁加锁会返回错误
RECURSIVE: 嵌套锁,允许同一线程多次锁定而不产生死锁,多次释放才能被别的线程锁定
DEFAULT: 默认为普通锁,排队获取锁
设置/获取锁类型
int pthread_mutexattr_settype(pthread_mutexattr_t* attr, int type);int pthread_mutexattr_gettype(pthread_mutexattr_t* attr, int *type);
线程互斥方法
– 创建互斥锁pthread_mutex_init(pthread_mutex_t *mutex, pthread_mutexattr_t *attr)– 互斥锁加锁pthread_mutex_lock(pthread_mutex_t *mutex)– 互斥锁解锁pthread_mutex_unlock(pthread_mutex_t *mutex)
Demo
#include <stdio.h>#include <pthread.h>#include <stdlib.h>#include <unistd.h>#include <string.h>pthread_mutex_t lock;// 声明一个互斥锁int g_num;void* ThreadFunc_lock1(void* param){ int iRet; while (g_num > 0) { iRet = pthread_mutex_lock(&lock);// 加锁,锁定这段资源(这里共享的g_num) if (iRet) { printf("lock error\n"); usleep(1000); } printf("thread1:%d\n", g_num); g_num--; pthread_mutex_unlock(&lock);// 解锁 usleep(1); } return NULL;}void* ThreadFunc_lock2(void* param){ int iRet; while (g_num > 0) { iRet = pthread_mutex_lock(&lock);// 加锁,锁定这段资源(这里共享的g_num) if (iRet) { printf("lock error\n"); usleep(1000); } printf("thead2:%d\n", g_num); g_num--; pthread_mutex_unlock(&lock);// 解锁 usleep(1); } return NULL;}int main(){ //pthread_mutex_init(&lock, NULL);// 初始化为默认锁 pthread_mutexattr_t attr; pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK); // 等价上面两句 lock = PTHREAD_MUTEX_ERRORCHECK; pthread_mutex_init(&lock, &attr); pthread_t tid1, tid2; g_num = 100; pthread_create(&tid1, NULL, ThreadFunc_lock1, NULL); pthread_create(&tid2, NULL, ThreadFunc_lock2, NULL); pthread_join(tid1, NULL); pthread_join(tid2, NULL); return 0;}
所有示例的makefile
.PHONY:clean allSRC=$(wildcard *.c) # 找出所有当前目录的.c文件OBJ=$(SRC:%.c=%.o) # 把SRC所有的.c文件赋值给.o文件BIN=$(OBJ:%.o=%) # 去掉所有的.oCC=gcc # CC默认表示gccCFLAGS=-g -Wall # gcc 编译参数-g -WallLIBS=-lpthread # 依赖的库目录# $<: 依赖的第一个文件# $^:所有的依赖文件# $@:就是目标文件%# 生成的目标文件是all,目标文件依赖所有的BIN文件# 此处使用了makefile的自动推导功能,OBJ是.o文件,makefile就会去找怎么生成.o文件all:clean $(BIN) $(BIN):%:%.c $(CC) $(CFLAGS) $< -o $@ $(LIBS)clean: rm -rf $(BIN) $(OBJ)
- linux多线程
- linux多线程
- Linux多线程
- linux多线程
- linux多线程
- linux多线程~
- LINUX多线程
- linux多线程
- Linux多线程
- linux多线程
- linux多线程
- linux多线程
- linux多线程
- linux 多线程
- Linux多线程
- linux 多线程
- Linux多线程
- LINUX 多线程
- matrix67大神
- 验证码生成程序,包括成语验证码
- 微软混合开发经验总结
- Spring 4.2.5 + Hibernate 5.2.10 报错笔记
- java IO流读取保存图片文件
- Linux 多线程
- 2017年Java面试题整理
- CodeForce Round 446 Pride
- Node.js 新计划:使用 V8 snapshot 将启动速度提升 8 倍
- CentOS 7.0 安装配置LAMP服务器方法(Apache+PHP+MariaDB)
- 虚函数表
- linux 通配符(wildcard)
- 718. Maximum Length of Repeated Subarray
- 【mysql 执行计划】读懂mysql 中的执行计划