线程
1>线程是函数的一次执行过程,该函数成为线程函数
2>线程的作用
由于进程的地址空间时私有的,因此在进程间上下文切换时,系统开销比较大,
为了提高系统的性能,需要操作系统规范里引入了轻量级进程的概念,被称为线程
1>进程的切换非常耗资源
2>线程是一个微量级的进程
3>线程是CPU调度的最小单位
线程的相关API /编译需加//Compile and link with -pthread
1>线程的创建
#include <pthread.h>
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg);
功能:
创建线程(在编译带有线程的程序时,后面要带上 -pthread)
参数:
thread:线程的标志(返回的ID号)
attr:线程的属性:一般给NULL,NULL即为线程的默认属性:非分离属性线程(默认)、分离式属性线程
start_routine:函数指针,这是线程要执行的操作
void *(*start_routine) (void *)
arg:给线程函数传入的参数
返回值:
成功返回0
失败返回错误码,并且线程不会被创建
例子:
void *show()
{
}
pthread_t thread;
if(pthread_create(&thread,NULL,show,NULL)){ //再次创建线程,调用函数可以调用相同,但失去线程的特性
printf("pthread_create error");
}
2>线程的结束
pthread_exit();
#include <pthread.h>
void pthread_exit(void *retval);
Compile and link with -pthread.
功能:
结束当前线程(在编译带有线程的程序时,后面要带上 -pthread)
参数:
retval:线程退出的状态,NULL,"我死了,老王帮我照顾我老婆\n"----收尸
返回值:没有返回值
例子:
pthread_exit("进程嘎了\n");
3>线程的收尸
#include <pthread.h>
int pthread_join(pthread_t thread, void **retval);
Compile and link with -pthread.
功能:
给线程收尸---*/*阻塞属性*/ 释放资源
参数:
thread:线程的标志(给谁收)
retval:线程退出的状态
返回值:
成功返回0
失败返回错误码
例子:
char **retval;
pthread_join(thread,(void **)retval);
printf("%s\n",*retval);//打印死亡状态
4>线程的属性
非分离:为线程的默认状态,非分离要使用线程收尸的函数才可以释放资源
分离: 一般是自己设置,分离函数在线程结束后自动释放资源
第一种方式:相关API
操作
1>初始化属性
#include <pthread.h>
int pthread_attr_init(pthread_attr_t *attr);
Compile and link with -pthread.
功能:
初始化属性
参数:
attr:属性
返回值:
成功返回0
失败返回错误码
2>设置属性
#include <pthread.h>
int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);
功能:
设置属性
参数:attr:属性
detachstate:属性值(分离属性,非分离属性)
PTHREAD_CREATE_DETACHED
PTHREAD_CREATE_JOINABLE
返回值:
成功返回0
失败返回错误码
3>创建线程
pthread_create
4>销毁属性
#include <pthread.h>
int pthread_attr_destroy(pthread_attr_t *attr);
例子:
pthread_attr_t attr; //定义属性
//第一步:初始化
if(pthread_attr_init(&attr)){
perror("pthread_attr_init error");
exit(-1);
}
//第二步:设置属性
if(pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED)){
perror("pthread_attr_setdetachstate error");
exit(-1);
}
//第三步:创建线程
pthread_t thread;
if(pthread_create(&thread,&attr,show,NULL)){
perror("pthread_create error");
}
//第四步:销毁属性
if(pthread_attr_destroy(&attr)){
perror("tphread_attr_destroy error");
exit(-1);
}
第二种方式:
1>设置非分离属性:
pthread_create(thread,NULL,.....);
2>设置分离属性:
#include <pthread.h>
int pthread_detach(pthread_t thread);
Compile and link with -pthread.
功能:设置分离属性:
参数:thread(给谁设)
返回值:成功返回0
失败返回错误码
用法:
第一步:
需要先把线程以非分离的形式创建
pthread_create(&thread,NULL,.....);
第二步:
设置分离属性
phtread_detach(thread);
总结:
pthread_create(&thread,NULL,.....);
phtread_detach(thread);
二、线程的同步和互斥
1>线程的同步
通过信号灯来执行
1>信号灯的初始化
2>实现信号的的PV操作
相关API:
1>初始化
#include <semaphore.h>
int sem_init(sem_t *sem, int pshared, unsigned int value);
Link with -pthread.
功能:
信号灯的初始化
参数:
sem:信号灯的标识
pshared:0--->允许进程可以使用这个信号灯
value:值
返回值:
成功返回0
失败返回-1,并设置错误码
例子:
sem_t sem;
sem_init(&sem,0,0)
2>PV操作 P为申请资源操作,V为释放资源操作
P操作://等待资源
#include <semaphore.h>
int sem_wait(sem_t *sem);
功能:
当一个线程调用Wait操作时,它要么得到资源然后将信号量减一,
要么一直等下去(指放入阻塞队列),直到信号量大于等于一时。
P操作
参数:
sem:信号灯的标识
返回值:
成功返回0
失败返回-1,并设置错误码
例子:
sem_wait(&sem);
V操作
#include <semaphore.h>
int sem_post(sem_t *sem);
功能:
实际上是在信号量上执行加一操作,对应于车辆离开停车场,
该操作之所以叫做“释放”是因为释放了由信号量守护的资源。
V操作
参数:
sem:信号灯的标识
返回值
成功返回0
失败返回-1,并设置错误码
例子:
sem_post(&sem);
2>线程的互斥(线程的锁)
相关API(注意:线程的锁函数man不出来要执行某个命令才可以man):
可以man 锁的命令:sudo apt-getinstall manpages-posix-dev
1>初始化锁
pthread_mutex_init
#include <pthread.h>
int pthread_mutex_init(pthread_mutex_t *restrict mutex,
const pthread_mutexattr_t *restrict attr);
功能:
初始化互斥锁
参数:
mutex:锁
attr:NULL为互斥锁
返回值:
成功返回0
失败返回错误码
例子:
pthread_mutex_t ptm;//定义锁
pthread_mutex_init(&ptm,NULL)
2>使用锁
pthead_mutex_lock
#include <pthread.h>
int pthread_mutex_lock(pthread_mutex_t *mutex);
功能:
使用锁
参数:
mutex:锁
返回值:
成功返回0
失败返回错误码
例子:
pthead_mutex_lock(&ptm);
3>解锁
#include <pthread.h>
int pthread_mutex_unlock(pthread_mutex_t *mutex);
功能:
解开锁
参数:
mutex:锁
返回值:
成功返回0
失败返回错误码
4>销毁锁
pthread_mutex_destory
#include <pthread.h>
int pthread_mutex_destroy(pthread_mutex_t *mutex);
功能:
销毁锁
参数:
mutex:锁
返回值:
成功返回0
失败返回错误码
例子:
pthread_mutex_destory(&ptm);