目录
一、线程
1.线程接口相关函数
(1)创建线程
(2)结束线程
(3)等待线程
2.线程间通信
(1)同步
(2)互斥
每一个进程的地址空间是相互独立的
每一个进程都有一个叫task_struct任务结构体
在进行进程切换时需要不断刷新cache缓存,比较消耗资源
为了减少cache刷新时的资源消耗,引入了轻量级进程,称为线程。
线程特点:
同一个进程创建的多个线程,共用同一个进程的地址空间
进程创建线程后,我们把原本进程也可以称为线程,称为主线程
进程被称为最小的资源分配单位
线程称为最小的任务调度单位
线程公共数据:
用户名、用户组名
静态数据、全局数据(线程通信时使用)
文件描述符
私有数据:
线程ID
pc
优先级、状态、属性
堆栈
pthread_create() 创建线程
pthread_exit() 结束线程
pthread_join() 等待线程
#include
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg);
在编译与线程操作相关的程序时,需要连接线程库,线程库的库名 --pthread
Compile and link with -pthread.(要链接线程库)参数:
thread:线程对象,一个线程对应一个对象(唯一标识一个线程)
attr:线程属性,分离属性,结合属性(属性默认选项填NULL,结合属性)
start_routine(指针函数指针):线程处理函数,传入一个函数名
arg:给线程处理函数start_routine传参(结构体指针),如果线程处理函数没有参数,填NULL
返回值:
成功返回0,失败返回错误编号
eg:
void * func(void *);
int main()
{
pthread_t thread1;
char buf[]="bbbbbbb";
int ret=pthread_create(&thread1,NULL,func(),buf);
if(ret<0)
{
perror("pthread_create");
}
while(1)
{
printf("aaaaaaaaa\n");
sleep(1);
}
}
void *func(void *buf)
{
while(1)
{
puts((char *)buf);
sleep(1);
}
}
#include
void pthread_exit(void *retval);
参数:
retval:线程结束信息,由pthread_join等待接受,如果不想返回信息,则填空(给join提供返回值)
当结束主线程时,利用pthread_exit()结束不了其内的线程,应该使用exit()来结束主线程
#include
int pthread_join(pthread_t thread, void **retval);
等待线程一般在主线程结尾
参数:
thread:线程对象
retbal:传入一级指针的地址函数会阻塞程序,等到接收到制定线程对象的线程结束,如没有pthread_exit(),内的参数,则没有接收值。
void *buf=NULL;
pthread_join(thread1,&buf);
printf("%s\n",(char *)buf);/puts(buf);
线程间通信只需要利用全局变量就可以实现。
在一个线程使用全局变量时,有可能其他线程,也在访问该数据,那么某一线程使用的数据就可能遭到破坏。
通过线程的同步和互斥,能够达到数据保护的效果
同步可以规定多个线程的执行顺序,互斥不能规定线程的执行顺序,只能保证一个线程的执行过程中不会被其他线程打断
多个线程之间,按照事先约定好的顺序有先后的完成某个事件。
信号量:是系统中的一种资源,本质是一个非负整数,信号量的值等于资源个数 操作信号量只能通过特定函数接口访问:
sem_init() 资源数初始化为0
sem_wait() 资源数-1 有资源才用,没有就阻塞
sem_post() 资源数+1 唤醒阻塞的线程
sem_init() --信号量的初始化
sem_wait() --P操作(申请资源)
if(是否有资源)
{
执行后续代码;
信号量-1;
}
else
{
阻塞等待,直到有资源唤醒为止;
}
sem_post() --V操作(释放资源)
信号量+1;
if(有等待资源的程序)
{
将其唤醒;
}
#include
int sem_init(sem_t *sem, int pshared, unsigned int value);
信号量定为全局变量,在主线程中初始化
在编译与线程操作相关的程序时,需要连接线程库,线程库的库名 --pthread
参数:sem:信号量对象,一个对象对应一个信号量,全局变量
pshared:线程间同步填0
value:信号量的初始值,一般为0
在编译与线程操作相关的程序时,需要连接线程库,线程库的库名 --pthread
#include
int sem_wait(sem_t *sem);参数:
sem:要操作的互斥锁对象
返回值:
成功返回0,失败返回错误号
#include
int sem_post(sem_t *sem);参数:
sem:要操作的互斥锁对象
返回值:
成功返回0,失败返回错误号
练习:创建两个线程,一个线程从键盘获取数据,另一个线程打印输出。
/*===============================================
* 文件名称:communication.c
* 创 建 者:
* 创建日期:2022年08月09日
* 描 述:
================================================*/
#include
#include
#include
#include
#include
void *func1();
void *func2();
char buf[4]={0};//缓冲区,用于存储读取到的数据
sem_t sem; //信号量1
sem_t sem1; //信号量2
int main(int argc, char *argv[])
{
pthread_t thread1,thread2; //定义线程对象
sem_init(&sem,0,0);//初值设为0
sem_init(&sem1,0,1);//初值设为1,以便第一次输入
int ret1=pthread_create(&thread1,NULL,func1,NULL);//创建线程1
if(ret1<0)
{
perror("pthread_create");
exit(-1);
}
int ret2=pthread_create(&thread2,NULL,func2,NULL);//创建线程1
if(ret2<0)
{
perror("pthread_create");
exit(-1);
}
pthread_join(thread1,NULL); //阻塞主线程,等待
pthread_join(thread2,NULL);
return 0;
}
void *func1() //线程1的函数
{
while(1)
{
//printf(">:");
sem_wait(&sem1); // 1 -1 信号量2的初值为1,可以执行一次fgets。
fgets(buf,4,stdin);
sem_post(&sem);// 0 +1 信号量1的初值为0,加一后可以输出一次
}
}
void *func2() //线程函数2
{
while(1)
{
sem_wait(&sem); // 0 -1 信号量1初值为0,需等待fgets后的post加一之后才可以输出
fputs(buf,stdout);
sem_post(&sem1);// 1 +1 信号量2的初值为1,在fgets之前的wait时-1,
//这里的puts之后+1,以便进行下一次fgets
}
}
当一个线程使用公共数据时,其他线程都不能访问该共享数据
临界资源:公共资源,多个线程能够共同访问的数据(全局变量)
临界区:涉及到临界资源的代码模块
互斥是使用互斥锁来保护临界区。
互斥锁的相关操作接口函数
1.互斥锁的初始化--pthread_mutex_init()
int pthread_mutex_init(pthread_mutex_t *mutex,pthread_mutexattr *attr)
参数:互斥锁的对象,定义为全局变量,线程都能访问到
属性,填NULL缺省属性
返回值:
成功返回0,失败返回-1
2.申请锁--pthread_mutex_lock()
pthread_mutex_lock(pthread_mutex_t *mutex)
参数:
mutex,要操作的互斥锁对象
返回值:
成功返回0,失败返回错误号
3.释放锁--pthread_mutex_unlock()
pthread_mutex_unlock(pthread_mutex_t *mutex)
参数:
mutex,要操作的互斥锁对象
返回值:
成功返回0,失败返回错误号
/*===============================================
* 文件名称:mutec.c
* 创 建 者:
* 创建日期:2022年08月09日
* 描 述:
================================================*/
#include
#include
#include
void *func(); //函数声明
int num1=0; //全局变量
int num2=0;
int count=0;
pthread_mutex_t mutex;//互斥锁的对象
int main(int argc, char *argv[])
{
pthread_t thread; //线程的对象
pthread_mutex_init(&mutex,NULL); //互斥锁的初始化
int ret=pthread_create(&thread,NULL,func,NULL);//线程的创建
if(ret<0)
{
perror("pthread_create");
exit(-1);
}
while(1)
{
pthread_mutex_lock(&mutex); //加锁
num1=count;
num2=count;
count++;
pthread_mutex_unlock(&mutex); //解锁
}
return 0;
}
void *func()
{
while(1)
{
pthread_mutex_lock(&mutex); //加锁
if(num1!=num2)
{
printf("num1=%d num2=%d\n",num1,num2);
}
pthread_mutex_unlock(&mutex);//解锁
}
}