一.进程基础
1.线程:进程内部的一条执行路径(序列),一个进程可以包含多个线程 进程:一个正在运行的程序
2.创建线程:pthread_create()
退出线程:pthread_exit() --->退出进程:exit()
等待线程结束:pthread_join
3.一个函数对应一个线程
4. int pthread_create(pthread_t *thread(线程id),const pthred_attr_t*attr(线程属性一般不设置,填NULL即可),void*(*start_routine)(void*)(线程函数,有几个线程就创建几个线程函数,参数为void*,返回值为void*的函数指针),void*arg(线程函数的参数))----->创建线程
int pthread_join(pthread_t thread(线程id),void**retval(接收线程函数返回主线程的一些信息))--->等待线程结束,线程未结束会阻塞住
int pthread_t exit(void *retval(传一个信息给主线程))--->退出线程
5.线程编译:
6.两个线程并发进行:子线程与主线程同时进行,子线程与子线程同时进行,并不是函数调用
#include<stdio.h>
#include<pthread.h>//线程的头文件
void*fun(void*arg)//线程函数,返回值为void*类型,参数为void*类型
{
for(int i=0;i<5;i++)
{
printf("fun run\n");
sleep(1);
}
pthread_t exit("fun over");//传给指针s
}
int main()
{
pthread_t id;//定义线程Id
pthread_create(&id,NULL,fun,NULL);//第二个NULL为传给线程函数的参数
for(int i=0;i<5;i++)
{
printf("main run\n");
sleep(1);
}
char *s=NULL;
pthread_join(id,(void**)&s);//接收s若子线程未结束则阻塞
pthread_join(id,NULL);//子线程未结束则阻塞,不用接收返回值
printf("s=%s\n",s);
exit(0);
}
7.进程并行:并发运行-->交替进行(1个处理器) 并行:-->同时进行(2个以上处理器)
①没次打印的值是随机的,并不一定是0-4,可能有重复的
#include<stdio.h>
#include<pthread.h>//线程的头文件 有多个处理器可以多个执行,单个处理器单个执行
void*fun(void*arg)//线程函数,返回值为void*类型,参数为void*类型 创建好5个线程但调度执行顺序是随机的
{
int *p=(int*)arg;
int index=*p;
printf("index=%d\n",index);
}
int main()
{
pthread_t id[5];//定义5个线程Id
int i=0;
for(;i<5;i++)
{
pthread_create(&id[i],NULL,fun,&i);//传id[i]的地址,将id存入数组中
}
for(i=0;i<5;i++)
{
pthread_join(id,NULL);//子线程未结束则阻塞,不用接收返回值
}
exit(0);
}
②这样改后就不会出现随机,只会是0-4
#include<stdio.h>
#include<pthread.h>//线程的头文件 有多个处理器可以多个执行,单个处理器单个执行
void*fun(void*arg)//线程函数,返回值为void*类型,参数为void*类型 创建好5个线程但调度执行顺序是随机的
{
int *p=(int*)arg;
int index=*p;
printf("index=%d\n",index);
free(p);//此时p指向malloc所指向的空间
}
int main()
{
pthread_t id[5];//定义5个线程Id
int i=0;
for(;i<5;i++)
{
int *s=(int*)malloc(sizeof(int));//申请空间将i的值给到堆区空间
*s=i;
pthread_create(&id[i],NULL,fun,(void*)s);//传id[i]的地址,将id存入数组中
}
for(i=0;i<5;i++)
{
pthread_join(id,NULL);//子线程未结束则阻塞,不用接收返回值
}
exit(0);
}
③从1开始创建5个线程,每个线程加1000,在多个处理器下,结果可能小于等于5000,原因是在多个线程运行时,不同的处理器可能同时进行一个操作,导致有重复的数出现,结果小于了5000
#include<stdio.h>
#include<pthread.h>//线程的头文件 有多个处理器可以多个执行,单个处理器单个执行
int g_val=1;
void*fun(void*arg)//线程函数,返回值为void*类型,参数为void*类型 创建好5个线程但调度执行顺序是随机的
{
for(int i=0;i<1000;i++)
{
printf("g_val=%d\n",g_val++);
}
}
int main()
{
pthread_t id[5];//定义5个线程Id
int i=0;
for(;i<5;i++)
{
pthread_create(&id[i],NULL,fun,NULL);//传id[i]的地址,将id存入数组中
}
for(i=0;i<5;i++)
{
pthread_join(id,NULL);//子线程未结束则阻塞,不用接收返回值
}
exit(0);
}
8 ./main >file.txt (将结果写到一个文件中)
9.查看文件中重复的值:uniq -d file.txt(-d只会查看重复行)
二.线程同步
1.线程同步:信号量,互斥锁,读写锁,条件变量
2.信号量:初始值可以自己设置,有顺序的就用信号量
sem_init(sem_t*sem(信号量地址),int pshared(能否在两个进程间共享,一般为0),unsigned int value(初始值))-->初始化
sem_wait(sem_t*sem(信号量地址))-->p操作 获取资源
sem_post(sem_t*sem(信号量地址))-->v操作 释放资源
sem_destroy(sem_t*sem(信号量地址))-->销毁
3.互斥锁:解决互斥性场所,信号量也可以满足这个,不要求顺序可以用互斥锁
pthread_mutex_init(pthread_mutex_t * restrict mutex(锁变量地址),const pthread_mutexattr_t *restrict attr(属性,一般给NULL))-->初始化互斥锁
pthread_mutex_lock(pthread_mutex_t *mutex(锁变量地址))-->加锁,阻塞
pthread_mutex_unlock(pthread_mutex_t *mutex(锁变量地址))-->解锁
pthread_mutex_destroy(pthread_mutex_t *mutex(锁变量地址))-->销毁锁
4.使用信号量与互斥锁解决:从1开始创建5个线程,每个线程加1000,在多个处理器下,使结果等于5000
#include<stdio.h>
#include<pthread.h>//线程的头文件 有多个处理器可以多个执行,单个处理器单个执行
#incldue<semaphore.h>//线程信号量头文件
//sem_t sem;//信号量
pthread_mutex_t metux//锁变量
int g_val=1;
void*fun(void*arg)//线程函数,返回值为void*类型,参数为void*类型
{
for(int i=0;i<1000;i++)
{
//sem_wait(&sem);//p操作
pthread_mutex_lock(&metux);//加锁
printf("g_val=%d\n",g_val++);
pthread_mutex_unlock(&metux);//解锁
//sem_post(&sem);//v操作
}
}
int main()
{
pthread_t id[5];//定义5个线程Id
//sem_init(&sem,0,1);//0为不能在两个进程间共享,1为信号量初始值为1
//pthread_mutex_init(&metux,NULL);
int i=0;
for(;i<5;i++)
{
pthread_create(&id[i],NULL,fun,NULL);//传id[i]的地址,将id存入数组中
}
for(i=0;i<5;i++)
{
pthread_join(id,NULL);//子线程未结束则阻塞,不用接收返回值
}
pthread_mutex_destroy(&metux);
//sem_destroy(&sem);
exit(0);
}
5.三条执行路径打印ABC ABC ABC ABC ABC
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
#include <semaphore.h>
sem_t sema;
sem_t semb;
sem_t semc;
void* funa(void* arg)
{
for(int i = 0; i < 5; i++ )
{
sem_wait(&sema);//ps1
printf("A");
fflush(stdout);
sem_post(&semb);//vs2
}
}
void * funb(void* arg)
{
for(int i = 0; i < 5; i++ )
{
sem_wait(&semb);//ps2
printf("B");
fflush(stdout);
sem_post(&semc);//vs3
}
}
void * func(void* arg)
{
for(int i = 0; i < 5; i++ )
{
sem_wait(&semc);//ps3
printf("C");
fflush(stdout);
sem_post(&sema);//vs1
}
}
int main()
{
sem_init(&sema,0,1);
sem_init(&semb,0,0);
sem_init(&semc,0,0);
pthread_t id1, id2,id3;
pthread_create(&id1,NULL,funa,NULL);
pthread_create(&id2,NULL,funb,NULL);
pthread_create(&id3,NULL,func,NULL);
pthread_join(id1,NULL);
pthread_join(id2,NULL);
pthread_join(id3,NULL);
sem_destroy(&sema);
sem_destroy(&semb);
sem_destroy(&semc);
exit(0);
}