一、线程
1、定义
进程的创建、销毁与切换存在着较大的时空开销,因此人们急需一种轻型的进程技术来减少开销。在80年代,线程的概念开始出现,线程被设计成进程的一个执行路径,同一个进程中的线程共享进程的资源,因此系统对线程的调度所需的成本远远小于进程。
2、特性
①线程是一个基本的CPU执行单元,也是程序执行流的最小单位。
②每个线程都有一个线程TID、线程控制块(TCB)
③同一进程的不同线程间共享进程的资源
3、实现方式
4、线程与进程的区别
本质区别:进程是操作系统资源分配的基本单位,而线程是CPU任务调度和执行的基本单位。
包含关系:一个进程至少有一个线程,线程是进程的一部分,所以线程也被称为轻权进程或者轻量级进程。
资源开销:每个进程都有独立的地址空间,进程之间的切换会有较大的开销;线程可以看做轻量级的进程,同一个进程内的线程共享进程的地址空间,每个线程都有自己独立的运行栈和程序计数器,线程之间切换的开销小。
影响关系:一个进程崩溃后,在保护模式下其他进程不会被影响,但是一个线程崩溃可能导致整个进程被操作系统杀掉,所以多进程要比多线程健壮。
5、相关函数
pthread_create
函数功能:
用于创建对应的线程,并且线程会立即执行
头文件:
#include <pthread.h>
函数原型:
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);
函数参数:
pthread_t *thread:用于存储新创建的线程的标识符(tid)
const pthread_attr_t *attr:指向线程属性对象的指针,设置为 NULL 以使用默认属性
void *(*start_routine) (void *):指向线程函数的指针,这个线程函数是线程开始执行时调用的函数(线程处理函数),线程处理函数的名字:void *pthread_task(void *arg)
void *arg:传递给线程处理函数的参数,这个参数的值将被传递给 start_routine 函数
函数返回值:
成功 返回0
失败 返回-1
注意:当你声明一个 pthread_t 类型的变量时,你实际上是在为该线程分配一个标识符(tid),但这个标识符本身在声明时并不会被自动初始化或分配给一个实际的线程
示例1:利用pthread_create函数,创建一个子线程,观察一下。
现象:
代码:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <pthread.h>
//线程处理函数
void *pthread_task(void *arg)
{
printf("hello_world\r\n");
}
int main(int argc,char* argv[])
{
//生成线程的标识符
pthread_t tid;
int ret;
//创建线程
ret = pthread_create(&tid,NULL, pthread_task, NULL);
if(ret == 0)
{
printf("pthread create success\r\n");
}
//输出一下tid
printf("tid:%ld\r\n",tid);
while(1);
return 0;
}
示例2:利用pthread_create函数,将对应的参数(数字),传递给对应的线程处理函数。
现象:
代码:
include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <pthread.h>
//线程处理函数
void *pthread_task(void *arg)
{
//输出对应的arg long --类型
long a=(long)arg;
printf("a=%ld\r\n",a);
printf("task%ld=hello\r\n",a);
}
int main(int argc,char* argv[])
{
//生成线程的标识符
pthread_t tid;
int ret;
//创建线程
ret = pthread_create(&tid,NULL, pthread_task, (void *)1);
if(ret == 0)
{
printf("pthread create success\r\n");
}
printf("tid:%ld\r\n",tid);
while(1);
return 0;
}
示例3:利用pthread_create函数,将对应的参数,传递给对应的线程处理函数。-传递参数是变量
现象:
代码:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <pthread.h>
//线程处理函数
void *pthread_task(void *arg)
{
//输出对应的arg long --类型
int a=*(int*)arg;
printf("a=%d\r\n",a);
printf("task%d=hello\r\n",a);
}
int main(int argc,char* argv[])
{
//生成线程的标识符
pthread_t tid;
int ret;
//定义变量
int a = 10;
//创建线程
ret = pthread_create(&tid,NULL, pthread_task, (void *)&a);
if(ret == 0)
{
printf("pthread create success\r\n");
}
printf("tid:%ld\r\n",tid);
while(1);
return 0;
}
示例4:利用pthread_create函数,传递一个结构体,观察一下
现象:
代码:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <pthread.h>
//声明一个结构体
struct test{
int test1;
char test2;
};
//线程处理函数
void *pthread_task(void *arg)
{
//输出对应的arg long --类型
struct test* a=(struct test*)arg;
printf("test1=%d\r\n",a->test1);
printf("test2=%c\r\n",a->test2);
printf("task%d=hello\r\n",a->test1);
}
int main(int argc,char* argv[])
{
//生成线程的标识符
pthread_t tid;
int ret;
//定义结构体变量
struct test a={10,'c'};
//创建线程
ret = pthread_create(&tid,NULL, pthread_task, (void *)&a);
if(ret == 0)
{
printf("pthread create success\r\n");
}
printf("tid:%ld\r\n",tid);
while(1);
return 0;
}
pthread_exit
函数功能:
退出当前的一个线程
头文件:
#include <pthread.h>
函数原型:
void pthread_exit(void *retval);
函数参数:
void *retval:传递的数据,如果线程不需要返回任何特定的值,可以传递 NULL。
函数返回值:无
示例:调用一下退出函数,pthread_exit函数,观察一下对应的现象
现象:
代码:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <pthread.h>
//声明一个结构体
struct test{
int test1;
char test2;
};
//线程处理函数
void *pthread_task(void *arg)
{
//输出对应的arg long --类型
struct test* a=(struct test*)arg;
printf("test1=%d\r\n",a->test1);
printf("test2=%c\r\n",a->test2);
//退出当前线程
pthread_exit(NULL);
printf("task%d=hello\r\n",a->test1);
}
int main(int argc,char* argv[])
{
//生成线程的标识符
pthread_t tid;
int ret;
//定义结构体变量
struct test a={10,'c'};
//创建线程
ret = pthread_create(&tid,NULL, pthread_task, (void *)&a);
if(ret == 0)
{
printf("pthread create success\r\n");
}
printf("tid:%ld\r\n",tid);
while(1);
return 0;
}
pthread_join
函数功能:
等待对应的子线程运行结束,并且获取子线程传递过来的参数
头文件:
#include <pthread.h>
函数原型:
int pthread_join(pthread_t thread, void **retval);
函数参数:
pthread_t thread:对应创建子线程的tid号
void **retval:对应的子线程退出的时候,传递的参数可以接收一下
函数返回值:
成功 返回0
失败 返回-1
示例:利用pthread_join函数,可以等待对应的子线程运行结束,观察对应的现象
现象:
代码:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <pthread.h>
//声明一个结构体
struct test{
int test1;
char test2;
};
//线程处理函数
void *pthread_task(void *arg)
{
//输出对应的arg long --类型
struct test* a=(struct test*)arg;
printf("test1=%d\r\n",a->test1);
printf("test2=%c\r\n",a->test2);
printf("task%d=hello\r\n",a->test1);
//退出当前线程
pthread_exit(NULL);
}
int main(int argc,char* argv[])
{
//生成线程的标识符
pthread_t tid;
int ret;
//定义结构体变量
struct test a={10,'c'};
//创建线程
ret = pthread_create(&tid,NULL, pthread_task, (void *)&a);
if(ret == 0)
{
printf("pthread create success\r\n");
}
printf("tid:%ld\r\n",tid);
//等待线程结束
ret = pthread_join(tid,NULL);
if(ret == 0)
printf("exit success\r\n");
return 0;
}
pthread_cancel
函数功能:
取消对应线程的执行
头文件:
#include <pthread.h>
函数原型:
int pthread_cancel(pthread_t pthread);
函数参数:
pthread_t thread:对应创建子线程的tid号
函数返回值:
成功 返回0
失败 返回-1
补充:该函数执行后,目标线程不一定立即执行,需要满足条件—一般情况下,子线程执行完毕
示例:利用pthread_cancel函数,取消对应的子线程运行,观察对应的现象
现象:
代码:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <pthread.h>
//声明一个结构体
struct test{
int test1;
char test2;
};
//线程处理函数
void *pthread_task(void *arg)
{
//输出对应的arg long --类型
struct test* a=(struct test*)arg;
printf("test1=%d\r\n",a->test1);
printf("test2=%c\r\n",a->test2);
printf("task%d=hello\r\n",a->test1);
//退出当前线程
pthread_exit(NULL);
}
int main(int argc,char* argv[])
{
//生成线程的标识符
pthread_t tid;
int ret;
//定义结构体变量
struct test a={10,'c'};
//创建线程
ret = pthread_create(&tid,NULL, pthread_task, (void *)&a);
if(ret == 0)
{
printf("pthread create success\r\n");
}
printf("tid:%ld\r\n",tid);
//取消对应的子线程
ret = pthread_cancel(tid);
printf("ret:%d\r\n",ret);
//等待线程结束
ret = pthread_join(tid,NULL);
if(ret == 0)
printf("exit success\r\n");
return 0;
}
综合实例
示例1:利用两个子线程实现交替报数---子线程1—1 子线程2---2
现象:
代码:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <pthread.h>
//线程1处理函数
void *pthread_task1(void *arg)
{
//输出对应的arg long --类型
int a=*(int*)arg;
sleep(1);
int i = 1;
while(1)
{
printf("task%d=%d\r\n",a,i);
i += 2;
sleep(2);
}
//退出当前线程
pthread_exit(NULL);
}
//线程2处理函数
void *pthread_task2(void *arg)
{
//输出对应的arg long --类型
int a=*(int*)arg;
sleep(1);
int i = 2;
while(1)
{
sleep(1);
printf("task%d=%d\r\n",a,i);
i += 2;
sleep(1);
}
//退出当前线程
pthread_exit(NULL);
}
int main(int argc,char* argv[])
{
//生成线程的标识符
pthread_t tid1,tid2;
int ret;
//定义结构体变量
int a = 1;
int b = 2;
//创建线程1
ret = pthread_create(&tid1,NULL, pthread_task1, (void *)&a);
if(ret == 0)
{
printf("pthread create success\r\n");
}
printf("tid1:%ld\r\n",tid1);
//创建线程2
ret = pthread_create(&tid2,NULL, pthread_task2, (void *)&b);
if(ret == 0)
{
printf("pthread create success\r\n");
}
printf("tid2:%ld\r\n",tid2);
//等待线程结束
ret = pthread_join(tid1,NULL);
if(ret == 0)
printf("exit success\r\n");
ret = pthread_join(tid2,NULL);
if(ret == 0)
printf("exit success\r\n");
return 0;
}
示例2:可以利用pthread_exit()传递参数,利用pthread_join()函数可以接收一下
现象:
代码:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <pthread.h>
//声明一个结构体
struct test{
int test1;
char test2;
};
//线程处理函数
void *pthread_task(void *arg)
{
//输出对应的arg long --类型
struct test* a=(struct test*)arg;
printf("test1=%d\r\n",a->test1);
printf("test2=%c\r\n",a->test2);
printf("task%d=hello\r\n",a->test1);
//退出当前线程
pthread_exit(86);
}
int main(int argc,char* argv[])
{
//生成线程的标识符
pthread_t tid;
int ret,result;
//定义结构体变量
struct test a={10,'c'};
//创建线程
ret = pthread_create(&tid,NULL, pthread_task, (void *)&a);
if(ret == 0)
{
printf("pthread create success\r\n");
}
printf("tid:%ld\r\n",tid);
//等待线程结束
ret = pthread_join(tid,(void *)&result);//result 已经是 void* 类型(通过转换)
if(ret == 0)
printf("exit success\r\n");
//观察退出线程返回的值
printf("result:%d\r\n",result);
return 0;
}
示例3:利用两个线程实现自由报数
现象:
代码:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <pthread.h>
int i = 1;
//线程处理函数
void *pthread_task(void *arg)
{
//输出对应的arg long --类型
int a=*(int*)arg;
while(1)
{
printf("task%d=%d\r\n",a,i);
i++;
sleep(1);
}
//退出当前线程
pthread_exit(NULL);
}
int main(int argc,char* argv[])
{
//生成线程的标识符
pthread_t tid1,tid2;
int ret;
//定义结构体变量
int a = 1;
int b = 2;
//创建线程1
ret = pthread_create(&tid1,NULL, pthread_task, (void *)&a);
usleep(1000);
//创建线程2
ret = pthread_create(&tid2,NULL, pthread_task, (void *)&b);
//等待线程结束
ret = pthread_join(tid1,NULL);
ret = pthread_join(tid2,NULL);
return 0;
}
示例4:利用三个线程实现交替报数
现象:
代码:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <pthread.h>
//线程1处理函数
void *pthread_task1(void *arg)
{
//输出对应的arg long --类型
int a=*(int*)arg;
int i = 1;
while(1)
{
printf("task%d=%d\r\n",a,i);
i += 3;
sleep(3);
}
//退出当前线程
pthread_exit(NULL);
}
//线程2处理函数
void *pthread_task2(void *arg)
{
//输出对应的arg long --类型
int b=*(int*)arg;
int i = 2;
while(1)
{
sleep(1);
printf("task%d=%d\r\n",b,i);
i += 3;
sleep(2);
}
//退出当前线程
pthread_exit(NULL);
}
//线程3处理函数
void *pthread_task3(void *arg)
{
//输出对应的arg long --类型
int c=*(int*)arg;
int i = 3;
while(1)
{
sleep(2);
printf("task%d=%d\r\n",c,i);
i += 3;
sleep(1);
}
//退出当前线程
pthread_exit(NULL);
}
int main(int argc,char* argv[])
{
//生成线程的标识符
pthread_t tid1,tid2,tid3;
int ret;
//定义结构体变量
int a = 1;
int b = 2;
int c = 3;
//创建线程1
ret = pthread_create(&tid1,NULL, pthread_task1, (void *)&a);
//创建线程2
ret = pthread_create(&tid2,NULL, pthread_task2, (void *)&b);
//创建线程3
ret = pthread_create(&tid3,NULL, pthread_task3, (void *)&c);
//等待线程结束
pthread_join(tid1,NULL);
pthread_join(tid2,NULL);
pthread_join(tid3,NULL);
return 0;
}
示例5:利用线程实现冒泡排序的功能
思路:
./a.out 11 6 8 17 2
argv[0] argv[1] argv[2] argv[3] argv[4] argv[5]
现象:
代码:
代码:
法1:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <pthread.h>
//线程处理函数
void *pthread_task(void *arg)
{
//输出对应的arg long --类型
int a=*(int*)arg;
usleep(a*500);
printf(" %d",a);
//退出当前线程
pthread_exit(NULL);
}
int main(int argc,char* argv[])
{
//生成线程的标识符
pthread_t tid[argc-1];
int ret;
for(int i = 0;i < argc-1;i++)
{
//将字符转为整数
ret = atoi(argv[i+1]);
printf("ret%d:%d\r\n",i+1,ret);
//创建线程
pthread_create(&tid[i],NULL, pthread_task, (void *)&ret);
}
//等待线程结束
for(int i = 0;i < argc-1;i++)
{
pthread_join(tid[i],NULL);
}
printf("\n");
return 0;
}
//法2
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <pthread.h>
int buff[20]={0};
int i = 0;
//线程处理函数
void *pthread_task(void *arg)
{
//输出对应的arg long --类型
int a=buff[i++];
usleep(a*1000);
printf(" %d",a);
//退出当前线程
pthread_exit(NULL);
}
int main(int argc,char* argv[])
{
//生成线程的标识符
pthread_t tid[argc-1];
int ret;
for(int i = 0;i < argc-1;i++)
{
//将字符转为整数
ret = atoi(argv[i+1]);
printf("ret%d:%d\r\n",i+1,ret);
//存储到数组中
buff[i]=ret;
}
for(int i = 0;i < argc-1;i++)
{
//创建线程
pthread_create(&tid[i],NULL, pthread_task, NULL);
}
//等待线程结束
for(int i = 0;i < argc-1;i++)
{
pthread_join(tid[i],NULL);
}
printf("\n");
return 0;
}
二、互斥锁
1、定义
在线程(pthread)库中,互斥锁(mutex)是用于线程同步的一种机制,确保在同一时刻只有一个线程可以访问共享资源。Mutex是一种简单加锁函数控制对共享资源的存取,这个互斥锁只有两种状态(上锁和解锁),锁可以看出某种意义上的全局变量。
2、互斥锁操作流程
使用互斥锁步骤:
一个互斥锁,对应一个共享资源。
标注:主线程主要完成锁的初始化以及销毁锁 子线程里面涉及加锁和解锁的过程。
主线程:
第一步:创建并初始化互斥锁。
第二步:创建多个子线程。
第三步:等待子线程运行结束。
第四步:销毁互斥锁。
第五步:结束进程
子线程:
第一步:在操作共享资源之前上锁。
第二步:操作共享资源。
第三步:在操作共享资源以后解锁。
第四步:子线程运行结束
3、相关函数
pthread_mutex_init
函数功能:
运行时动态创建一个线程互斥锁
头文件:
#include <pthread.h>
函数原型:
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr);
函数参数:
thread_mutex_t *mutex:指向要初始化的互斥锁的指针。
const pthread_mutexattr_t *attr:用于指定互斥锁属性的对象指针,通常可以传递 NULL 以使用默认属性。
函数返回值:
成功 返回0
失败 返回-1
pthread_mutex_lock
函数功能:
锁定互斥锁
头文件:
#include <pthread.h>
函数原型:
int pthread_mutex_lock(pthread_mutex_t *mutex);
函数参数:
pthread_mutex_t *mutex: 指向要锁定的互斥锁的指针
函数返回值:
成功 返回0
失败 返回-1
注意:不论哪种类型的锁,都不能被两个不同的线程同时得到,必须等到解锁。
pthread_mutex_unlock
函数功能:
释放互斥锁(解锁)
头文件:
#include <pthread.h>
函数原型:
int pthread_mutex_unlock(pthread_mutex_t *mutex);
函数参数:
pthread_mutex_t *mutex: 指向要释放的互斥锁的指针
函数返回值:
成功 返回0
失败 返回-1
注意:释放锁之前必须确保当前线程已经锁定了该锁
pthread_mutex_destroy
函数功能:
销毁一个互斥锁,释放已经占有的共享资源
头文件:
#include <pthread.h>
函数原型:
int pthread_mutex_destroy(pthread_mutex_t *mutex);
函数参数:
pthread_mutex_t *mutex: 指向要销毁的互斥锁的指针
函数返回值:
成功 返回0
失败 返回-1
示例:基于互斥锁的所有API函数,观察上锁、解锁、摧毁锁的整个过程
现象:
代码:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <pthread.h>
//定义互斥锁
pthread_mutex_t lock;
//线程1处理函数
void *pthread_task1(void *arg)
{
//加锁
int ret = pthread_mutex_lock(&lock);
if(ret == 0)
printf("task1,success\r\n");
printf("hello\r\n");
//解锁
ret = pthread_mutex_unlock(&lock);
if(ret == 0)
printf("unlock success\r\n");
//退出当前线程
pthread_exit(NULL);
}
//线程2处理函数
void *pthread_task2(void *arg)
{
//加锁
int ret = pthread_mutex_lock(&lock);
if(ret == 0)
printf("task2,success\r\n");
printf("world\r\n");
//解锁
ret = pthread_mutex_unlock(&lock);
if(ret == 0)
printf("unlock success\r\n");
//退出当前线程
pthread_exit(NULL);
}
int main(int argc,char* argv[])
{
int ret;
pthread_t tid1,tid2;
//初始化互斥锁
ret = pthread_mutex_init(&lock, NULL);
if(ret == 0)
printf("lock init success\r\n");
//创建子线程
pthread_create(&tid1,NULL, pthread_task1, NULL);
pthread_create(&tid2,NULL, pthread_task2, NULL);
//等待线程结束
pthread_join(tid1,NULL);
pthread_join(tid2,NULL);
//摧毁互斥锁
ret = pthread_mutex_destroy(&lock);
if(ret == 0)
printf("destroy lock success\r\n");
return 0;
}
综合实例
综合1:利用线程互斥锁实现交替报数的功能
现象:
代码:
法1:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <pthread.h>
//定义互斥锁
pthread_mutex_t lock;
int i = 1;
//线程处理函数
void *pthread_task(void *arg)
{
int n = *(int *)arg;
//上锁
pthread_mutex_lock(&lock);
printf("task%d=%d\r\n",n,i);
i += 1;
//解锁
pthread_mutex_unlock(&lock);
//退出当前线程
pthread_exit(NULL);
}
int main(int argc,char* argv[])
{
//生成线程的标识符
pthread_t tid1,tid2,tid3;
int ret;
//初始化互斥锁
ret = pthread_mutex_init(&lock, NULL);
int a = 1;
int b = 2;
int c = 3;
while(1)
{
//创建线程1
pthread_create(&tid1,NULL, pthread_task,(void *)&a);
sleep(1);
//创建线程2
pthread_create(&tid2,NULL, pthread_task,(void *)&b);
sleep(1);
//创建线程3
pthread_create(&tid3,NULL, pthread_task,(void *)&c);
sleep(1);
}
//等待线程结束
pthread_join(tid1,NULL);
pthread_join(tid2,NULL);
pthread_join(tid3,NULL);
//摧毁互斥锁
ret = pthread_mutex_destroy(&lock);
if(ret == 0)
printf("destroy lock success\r\n");
return 0;
}
法2:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <pthread.h>
//定义互斥锁
pthread_mutex_t lock;
int i = 1;
//线程1处理函数
void *pthread_task1(void *arg)
{
int n = *(int *)arg;
while(1)
{
if(i%3==1)
{
//上锁
pthread_mutex_lock(&lock);
printf("task%d=%d\r\n",n,i);
i += 1;
//解锁
pthread_mutex_unlock(&lock);
}
else
sleep(1);//切换线程
}
//退出当前线程
pthread_exit(NULL);
}
//线程2处理函数
void *pthread_task2(void *arg)
{
int n = *(int *)arg;
while(1)
{
if(i%3==2)
{
//上锁
pthread_mutex_lock(&lock);
printf("task%d=%d\r\n",n,i);
i += 1;
//解锁
pthread_mutex_unlock(&lock);
}
else
sleep(1);//切换线程
}
//退出当前线程
pthread_exit(NULL);
}
//线程3处理函数
void *pthread_task3(void *arg)
{
int n = *(int *)arg;
while(1)
{
if(i%3==0)
{
//上锁
pthread_mutex_lock(&lock);
printf("task%d=%d\r\n",n,i);
i += 1;
//解锁
pthread_mutex_unlock(&lock);
}
else
sleep(1);//切换线程
}
//退出当前线程
pthread_exit(NULL);
}
int main(int argc,char* argv[])
{
//生成线程的标识符
pthread_t tid1,tid2,tid3;
int ret;
//初始化互斥锁
ret = pthread_mutex_init(&lock, NULL);
int a = 1;
int b = 2;
int c = 3;
//创建线程1
pthread_create(&tid1,NULL, pthread_task1,(void *)&a);
//创建线程2
pthread_create(&tid2,NULL, pthread_task2,(void *)&b);
//创建线程3
pthread_create(&tid3,NULL, pthread_task3,(void *)&c);
//等待线程结束
pthread_join(tid1,NULL);
pthread_join(tid2,NULL);
pthread_join(tid3,NULL);
//摧毁互斥锁
ret = pthread_mutex_destroy(&lock);
if(ret == 0)
printf("destroy lock success\r\n");
return 0;
}
法3:
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
//定义一个锁
pthread_mutex_t lock;
int i=1;
//线程的处理函数
void *pthread_task(void *arg)
{
long a=(long)arg;
while(1)
{
//加锁操作
pthread_mutex_lock(&lock);
printf("task%ld=%d\r\n",a,i);
i++;
//解锁函数
pthread_mutex_unlock(&lock);
sleep(1);
}
//退出线程
pthread_exit(NULL);
}
int main(int argc,char *argv[])
{
int ret;
pthread_t tid1,tid2,tid3;
//初始化线程互斥锁
ret=pthread_mutex_init(&lock,NULL);
if(ret == 0)
{
printf("pthread_mutex_init success\r\n");
}
//创建子线程
pthread_create(&tid1, NULL,pthread_task,(void *)1);
//创建子线程
pthread_create(&tid2, NULL,pthread_task,(void *)2);
//创建子线程
pthread_create(&tid3, NULL,pthread_task,(void *)3);
//等待对应的子线程运行结束
pthread_join(tid1,NULL);
pthread_join(tid2,NULL);
pthread_join(tid3,NULL);
//销毁对应的互斥锁
pthread_mutex_destroy(&lock);
return 0;
}
综合2:售票系统---模拟一个火车站的售票系统
分析思路:
1:对应的主函数里面(main---创建两个子线程(售票窗口—子线程1 退 票窗口—子线程2))
2:主线程里面可以等待对应子线程1和子线程2运行结束
3:子线程1(售票窗口)---提示一下当前是售票窗口---判断使用者是否购 票---如果购票,再进行处理。如果不购票,切换到(退票窗口)
4: 子线程2(退票窗口)---提示一下当前是退票窗口—判断使用者是否退票 —如果退票,再进行处理。如果不退票,切换到(售票窗口)
现象:
代码:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <pthread.h>
//定义互斥锁
pthread_mutex_t lock;
//票数
int check = 100;
//线程1处理函数---售票窗口
void *pthread_task1(void *arg)
{
char n;
while(1)
{
//上锁
pthread_mutex_lock(&lock);
//提示当前是售票窗口
printf("******************************************\r\n");
printf("------------------售票窗口----------------\r\n");
printf("******************************************\r\n");
//输入
printf("是否购票?请输入'Y'or'N\'\r\n");
scanf("%c",&n);
getchar();
//判断是否购票
if(n=='Y' || n=='y')
{
check--;
if(check == 0)
{
printf("车票售罄\r\n");
//解锁
pthread_mutex_unlock(&lock);//退出线程前需要解锁
break;
}
printf("购票成功,票数余量:%d\r\n",check);
//解锁
pthread_mutex_unlock(&lock);
sleep(1);
}
else
{
//解锁
pthread_mutex_unlock(&lock);
sleep(1);
}
}
//退出当前线程
pthread_exit(NULL);
}
//线程2处理函数---退票窗口
void *pthread_task2(void *arg)
{
char n;
while(1)
{
//上锁
pthread_mutex_lock(&lock);
//提示当前是退票窗口
printf("******************************************\r\n");
printf("------------------退票窗口----------------\r\n");
printf("******************************************\r\n");
//输入
printf("是否退票?请输入'Y'or'N\'\r\n");
scanf("%c",&n);
getchar();
if(n=='Y' || n=='y')
{
if(check == 100)
{
printf("车票已满\r\n");
//解锁
pthread_mutex_unlock(&lock);//退出线程前需要解锁
break;
}
printf("退票成功,票数余量:%d\r\n",++check);
//解锁
pthread_mutex_unlock(&lock);
sleep(1);
}
else
{
//解锁
pthread_mutex_unlock(&lock);
sleep(1);
}
}
//退出当前线程
pthread_exit(NULL);
}
int main(int argc,char* argv[])
{
char val;
//生成线程的标识符
pthread_t tid1,tid2;
//初始化互斥锁
pthread_mutex_init(&lock, NULL);
//创建线程1
pthread_create(&tid1,NULL, pthread_task1, NULL);
//创建线程2
pthread_create(&tid2,NULL, pthread_task2, NULL);
//等待线程结束
pthread_join(tid1,NULL);
pthread_join(tid2,NULL);
//摧毁互斥锁
pthread_mutex_destroy(&lock);
return 0;
}
说明:
CPU并发高速执行,几乎是同时的。
使用sleep函数阻塞(切换线程->CPU执行其它线程,直到sleep时间到,回来再继续执行当前线程),需要考虑sleep后是否有其它阻塞(scanf、fgetc\fgets....);特别是在多线程操作的时候,当前线程退出后,其它存在的线程再也无法切换到当前线程了
如下图: