1.多线程的创建
cs
#include <stdio.h>
#include <pthread.h>
typedef int u32;
//将一个函数指针类型重命名成PFUN_t类型
typedef void *(*PFUN_t)(void *);
void *main_ctl(void *arg)
{
while (1)
{
printf("主控模块正在工作...\n");
sleep(1);
}
}
void *get_cmd(void *arg)
{
while (1)
{
printf("获取指令模块正在工作...\n");
sleep(1);
}
}
void *ctl_cmd(void *arg)
{
while (1)
{
printf("执行指令模块正在工作...\n");
sleep(1);
}
}
void *get_pic(void *arg)
{
while (1)
{
printf("图像采集模块正在工作...\n");
sleep(1);
}
}
void *send_pic(void *arg)
{
while (1)
{
printf("图像发送模块正在工作...\n");
sleep(1);
}
}
int main(int argc, const char *argv[])
{
pthread_t tid[5];
// void *(*pfun)(void *); //函数指针 //指针名称:pfun
// void *(*pfuns[5])(void *) = {main_ctl, get_cmd}; //函数指针数组 //数组名:pfun
int a[10];
PFUN_t tasks[5] = {main_ctl, get_cmd, ctl_cmd, get_pic, send_pic};
for (int i = 0; i < 5; i++)
{
pthread_create(&tid[i], NULL, tasks[i],NULL);
}
while (1)
{
printf("xxxxx\n");
sleep(1);
}
pthread_join();
/*
pthread_create(&tid[0], NULL, main_ctl, NULL);
pthread_create(&tid[1], NULL, get_cmd, NULL);
pthread_create(&tid[2], NULL, ctl_cmd, NULL);
pthread_create(&tid[3], NULL, get_pic, NULL);
pthread_create(&tid[4], NULL, send_pic, NULL);
*/
for (int i = 0; i < 5; i++)
{
pthread_join(tid[i], NULL);
}
return 0;
}
2..线程的消亡
(1)线程退出
1)在线程任务函数中使用return结束线程
2)pthread_exit(NULL)退出线程;
void pthread_exit(void *retval);
功能: 退出一个线程任务
参数:retval:向回收的线程传递的参数的地址
NULL: 表示不传递参数
(2)线程回收
int pthread_join(pthread_t thread, void **retval);
功能: 阻塞等待回收线程资源空间
参数:thread:要回收的线程ID
retval:用来保存线程退出时传递的参数
NULL: 不接收传递的参数
返回值:成功:0
失败:-1
cs
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
//次线程
void *task(void *arg)
{
int i = 0;
while (1)
{
if (++i == 10)
{
char str[] = {"thread over!"};
// return "hello";
pthread_exit(NULL); // return NULL;
}
printf("I am thread : tid = %ld\n", pthread_self());
sleep(1);
}
printf("hello world\n");
return NULL;
}
int main(int argc, const char *argv[])
{
//主进程、主线程
pthread_t tid;
int ret = pthread_create(&tid, NULL, task, NULL);
if (ret !=0)
{
printf("pthread_create error\n");
return -1;
}
//void *retval;
pthread_join(tid, NULL);
//printf("retval -> %s\n", (char *)retval);
return 0;
}
线程回收策略:
分离属性的线程:不需要回收,由操作系统回收。(没有空闲的线程可帮忙回收时)
非分离属性的线程:pthread_join()阻塞回收
线程属性:1. 分离属性 :不需要被其他线程回收的线程称为分离属性得到线程,将来会被操作系统所回收
int pthread_detach(pthread_t thread);
功能:将线程设置成分离属性的线程
2. 非分离属性 :可以被其他线程回收或者结束的线程,称为非分离属性的线程(默认属性:非分离属性)
cs
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
//次线程
void *task(void *arg)
{
// printf("I am thread : tid = %ld\n", pthread_self());
}
int main(int argc, const char *argv[])
{
//主进程、主线程
pthread_t tid;
int i = 0;
while (1)
{
int ret = pthread_create(&tid, NULL, task, NULL);
if (ret !=0)
{
printf("pthread_create error\n");
return -1;
}
pthread_detach(tid);
i++;
printf("i = %d\n", i);
}
return 0;
}
返回值内存管理规则
静态/全局数据:
可以安全返回,因为生命周期是整个程序运行期间
字符串常量:
可以安全返回,如return "hello";
动态分配内存:
可以返回,但需要确保后续有释放机制
通常由接收线程负责释放
禁止返回:
自动局部变量(函数内非静态变量)
线程栈上的变量
3.线程间的通信
全局变量通信:
线程间互斥机制:
临界资源:多个线程可以同时访问的资源称为临界资源:比如,全局变量、共享内存区域等
多个线程在访问临界资源时,存在资源竞争问题。
如何解决资源竞争问题:
互斥机制:多个线程访问临界资源时,具有排他性访问的机制(一次只允许一个线程对该临界资源进行访问)。
互斥锁----->解决资源竞争问题。
实现步骤:
创建互斥锁:pthread_mutex_t
初始化互斥锁:pthread_mutex_init();
加锁:int pthread_mutex_lock(pthread_mutex_t *mutex);
解锁:int pthread_mutex_unlock(pthread_mutex_t *mutex);
销毁锁:int pthread_mutex_destroy(pthread_mutex_t *mutex);
int pthread_mutex_init(pthread_mutex_t *restrict mutex,
const pthread_mutexattr_t *restrict attr);
功能: 初始化互斥锁
参数:mutex:锁对象地址
attr:锁的属性 (NULL:默认属性)
返回值:成功:0
失败:-1
cs
#include <stdio.h>
#include <pthread.h>
int num_g = 0;
pthread_mutex_t mutex;
void *task1(void *arg)
{
pthread_mutex_lock(&mutex);
for(int i = 0; i < 100000; ++i)
{
num_g += 1;
printf("num_g = %d\n",num_g);
}
pthread_mutex_unlock(&mutex);
}
void *task2(void *arg)
{
pthread_mutex_lock(&mutex);
for(int i = 0; i < 100000; ++i)
{
num_g += 1;
printf("num_g = %d\n", num_g);
}
pthread_mutex_unlock(&mutex);
}
int main(int argc, char const *argv[])
{
pthread_t tid[2];
pthread_mutex_init(&mutex, NULL);
pthread_create(&tid[0], NULL, task1, NULL);
pthread_create(&tid[1], NULL, task2, NULL);
pthread_join(tid[0], NULL);
pthread_join(tid[1], NULL);
pthread_mutex_destroy(&mutex);
return 0;
}
4.函数指针的使用
1. 定义
返回值类型 (*指针名称)(形参表);
void *(*pfun)(void *);
2. 函数指针初始化
返回值类型 (*指针名称)(形参表)=函数的入口地址;
void *(*pfun)(void *) = main_ctl;
3. 函数指针赋值
函数指针名称=函数的入口地址;
void *(*pfun)(void *) = NULL;
pfun = main_ctl;
4. 函数指针怎么使用
函数名(实参表);
函数指针(实参表);
5. 函数指针的数组:保存多个函数指针
返回值类型 (*数组名称[n])(形参表);
void *(*pfun[5])(void *);