Linux软件编程-线程(2)

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;
}

线程回收策略:

  1. 分离属性的线程:不需要回收,由操作系统回收。(没有空闲的线程可帮忙回收时)

  2. 非分离属性的线程: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.线程间的通信

全局变量通信:

线程间互斥机制:

临界资源:多个线程可以同时访问的资源称为临界资源:比如,全局变量、共享内存区域等

多个线程在访问临界资源时,存在资源竞争问题。

如何解决资源竞争问题:

互斥机制:多个线程访问临界资源时,具有排他性访问的机制(一次只允许一个线程对该临界资源进行访问)。

互斥锁----->解决资源竞争问题。

实现步骤:

  1. 创建互斥锁:pthread_mutex_t

  2. 初始化互斥锁:pthread_mutex_init();

  3. 加锁:int pthread_mutex_lock(pthread_mutex_t *mutex);

  4. 解锁:int pthread_mutex_unlock(pthread_mutex_t *mutex);

  5. 销毁锁: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 *);

相关推荐
基于python的毕设1 小时前
C语言栈的实现
linux·c语言·ubuntu
luoqice1 小时前
linux下找到指定目录下最新日期log文件
linux·算法
林开落L2 小时前
库的制作与原理
linux·开发语言·动静态库·库的制作
共享家95273 小时前
linux-数据链路层
linux·网络·macos
Demisse4 小时前
[Linux] Linux文件系统基本管理
linux·运维·服务器
小米里的大麦5 小时前
025 理解文件系统
linux
打不了嗝 ᥬ᭄6 小时前
Linux 信号
linux·开发语言·c++·算法
禁默6 小时前
进程替换:从 “改头换面” 到程序加载的底层逻辑
linux·运维·服务器
gameatp6 小时前
从 Windows 到 Linux 服务器的全自动部署教程(免密登录 + 压缩 + 上传 + 启动)
linux·服务器·windows