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 *(*pfun5)(void *);

相关推荐
A小辣椒5 小时前
TShark:基础知识
linux
AlfredZhao7 小时前
OCI 明明分配了 200G 系统盘,为什么 df 只看到 30G?
linux·oci
AlfredZhao1 天前
vi 删除指定范围的行,不用再反复按 dd
linux·vi
用户9718356334661 天前
银河麒麟 KY10 申威(SW64) 安装 nginx-1.16.1-2.p01.ky10.sw_64.rpm 详细步骤
linux
猪脚踏浪1 天前
linux 拷贝文件或目录到指定的位置
linux
摇滚侠2 天前
Linux CentOS7 rpm 安装 MySQL 5.7
linux·运维·mysql
bush42 天前
嵌入式linux学习记录十四、术语
linux·嵌入式
载数而行5202 天前
Linux 11 动态监控指令top
linux
不会C语言的男孩2 天前
Linux 系统编程 · 第 8 章:进程基础
linux·c语言
古城小栈2 天前
Unix 与 Linux 异同小叙
linux·服务器·unix