嵌入式学习第二十二天!(继续学习线程)

news2024/11/18 9:50:09

线程相关函数接口:

1. 线程分离属性:

    线程结束后,自动回收线程空间

    1. pthread_attr_init:

int pthread_attr_init(pthread_attr_t *attr);

        功能:线程属性初始化

    2. pthread_attr_destroy:

int pthread_attr_destroy(pthread_attr_t *attr);

        功能:线程属性销毁

    3. pthread_attr_setdetachstate:

int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);

        功能:设置分离属性

            PTHREAD_CREATE_DETACHED   分离属性
            PTHREAD_CREATE_JOINABLE   加入属性(默认)

    练习:

       1. 利用线程的分离属性创建三个线程,打印线程id

#include "head.h"

void *thread1(void *arg)
{
	printf("stat to thread1(tid:%#x)\n", (unsigned int)pthread_self());
	return NULL;
}

void *thread2(void *arg)
{
	printf("stat to thread2(tid:%#x)\n", (unsigned int)pthread_self());
	return NULL;
}

void *thread3(void *arg)
{
	printf("stat to thread2(tid:%#x)\n", (unsigned int)pthread_self());
	return NULL;
}

int main(void)
{
	int i = 0;
	pthread_t thread[3];
	void *(*p[3])(void *) = {thread1, thread2, thread3};
	pthread_attr_t attr;

	pthread_attr_init(&attr);
	pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);

	for(i = 0; i < 3; i++)
	{
		pthread_create(&thread[i], &attr, p[i], NULL);
	}
	pthread_attr_destroy(&attr);

	while(1)
	{

	}

}

        2. 首先定义一个学生结构体,包含姓名、性别、年龄、分数。再创建两个两个线程,线程1负责从终端接收学生信息,线程2负责将学生信息打印在终端。

#include "head.h"

struct studet
{
	char name[100];
	char sex;
	int age;
	int score;
};

void *InputInfo(void *arg)
{
	struct studet *stu = arg;
	char *ptmp = stu->name;

	fgets(stu->name, 100, stdin);
	ptmp[strlen(ptmp)-1] = '\0';

	scanf("%c", &stu->sex);
	scanf("%d", &stu->age);
	scanf("%d", &stu->score);

	return NULL;
}

void *OutputInfo(void *arg)
{
	struct studet *stu = arg;
	
    sleep(5);
	printf("%s\n", stu->name);
	printf("%c\n", stu->sex);
	printf("%d\n", stu->age);
	printf("%d\n", stu->score);
	
	return NULL;
}

int main(void)
{
	struct studet t;
	pthread_t input;
	pthread_t output;
	
	pthread_create(&input, NULL, InputInfo, &t);
	pthread_create(&output, NULL, OutputInfo, &t);

	pthread_join(input, NULL);
    pthread_join(output, NULL);

	return 0;
}

2. 线程互斥:

    1. 互斥锁:

        防止资源竞争

    2. 函数接口:

        1. pthread_mutex_init:
int pthread_mutex_init(pthread_mutex_t *restrict mutex,
           const pthread_mutexattr_t *restrict attr);

            功能:互斥锁初始化

            参数:

                mutex:互斥锁空间首地址
                attr:互斥锁的属性(默认为NULL)

            返回值:

                成功返回0 
                失败返回错误码

        2. pthread_mutex_destroy:
int pthread_mutex_destroy(pthread_mutex_t *mutex);

            功能:互斥锁销毁

            参数:

                mutex:互斥锁空间首地址

            返回值:

                成功返回0 
                失败返回错误码

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

            功能:上锁

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

            功能:解锁

    3. 临界资源、临界区:

        加锁解锁中间的代码称为临界资源、临界区

        同一时刻临界资源不能同时执行,只能执行其中一个临界资源代码

    4. 原子操作:

        CPU最小的一次不能被任务调度打断的操作称为原子操作

    5. 注意:

        互斥锁只能解决资源竞争的问题,无法同步代码(没有先后执行的顺序关系)

    练习:

        定义三个整型的全局变量Num1, Num2,val,创建两个线程,一个线程循环令Num1=val,Num2=val,val自加;另一个线程,循环判断:当Num1不等于Num2的时候,输出Num1和Num2的值。利用互斥锁,让Num1始终等于Num2,使终端没有输出。

#include "head.h"

int val = 0;
int Num1 = 0;
int Num2 = 0;
pthread_mutex_t lock;

void *thread1(void *arg)
{
	while(1)
	{
		pthread_mutex_lock(&lock);
		Num1 = val;
		Num2 = val;
		pthread_mutex_unlock(&lock);
		val++;
	}
	return NULL;
}
void *thread2(void *arg)
{
	while(1)
	{
		pthread_mutex_lock(&lock);
		if(Num1 != Num2)
		{
			printf("Num1 = %d, Num2 = %d\n", Num1, Num2);
		}
		pthread_mutex_unlock(&lock);
	}
	return NULL;
}


int main(void)
{
	pthread_t tid1;
	pthread_t tid2;
	
	pthread_mutex_init(&lock, NULL);

	pthread_create(&tid1, NULL, thread1, NULL);
	pthread_create(&tid2, NULL, thread2, NULL);

	pthread_join(tid1, NULL);
	pthread_join(tid2, NULL);

	pthread_mutex_destroy(&lock);
	
	return 0;
}

3. 死锁:

    多线程操作互斥锁,导致多个线程均违法向下执行的状态称为死锁状态,简称为死锁

    1. 死锁产生的四个必要条件:

        1. 互斥条件

        2. 不可剥夺条件

        3. 请求保持

        4. 循环等待

    2. 如何避免产生死锁:

        1. pthread_mutex_trylock 替代 pthread_mutex_lock

        2. 加锁顺序保持一致

4. 信号量:

    信号量是一种资源,可以被初始化、申请、释放、销毁

    P操作:申请资源

    V操作:释放资源

    1. sem_init:

int sem_init(sem_t *sem, int pshared, unsigned int value);

        功能:初始化信号量

        参数:

            sem:信号量空间首地址

            pshared:为0的话,是一个进程中的所有线程间共享;非0的话,则是进程间共享

            value:初始化的值

        返回值:

           成功返回0 
           失败返回-1 

    2. sem_destory:

int sem_destroy(sem_t *sem);

        功能:信号量的销毁

        参数:

            sem:信号量空间首地址

        返回值:

            成功返回0 
            失败返回-1

    3. sem_wait:

int sem_wait(sem_t *sem);

        功能:申请信号量

    4. sem_post:

int sem_post(sem_t *sem);

        功能:释放信号量

作业:

        1. 创建三个线程分别循环打印 A B C,要求打印出来的顺序总是 A -> B -> C

#include "head.h"

sem_t sem_a;
sem_t sem_b;
sem_t sem_c;

void *thread1(void* arg)
{
	while(1)
	{
		sem_wait(&sem_a);
		printf("A\n");
		sem_post(&sem_b);
	}

	return NULL;
}
void *thread2(void* arg)
{
	while(1)
	{
		sem_wait(&sem_b);
		printf("B\n");
		sem_post(&sem_c);
	}

	return NULL;
}
void *thread3(void* arg)
{
	while(1)
	{
		sem_wait(&sem_c);
		printf("C\n");
		sem_post(&sem_a);
	}

	return NULL;
}

int main(void)
{
	int i = 0;
	pthread_t tid[3];
	void *(*p[3])(void *) = {thread1, thread2, thread3};
	
	sem_init(&sem_a, 0, 1);
	sem_init(&sem_b, 0, 0);
	sem_init(&sem_c, 0, 0);

	for(i = 0; i < 3; i++)
	{
		pthread_create(&tid[i], NULL, p[i], NULL);
	}

	for(i = 0; i < 3; i++)
	{
		pthread_join(tid[i], NULL);
	}

	sem_destroy(&sem_a);
	sem_destroy(&sem_b);
	sem_destroy(&sem_c);

	return 0;

}

        2. PTA | 程序设计类实验辅助教学平台

#include <stdio.h>

struct student
{
	char number[20];
	int testbit;
	int exambit;
};

int GetStudentBit(struct student *pstu, int maxlen)
{
	int n = 0;
	int i = 0;

	scanf("%d", &n);

	if(n > maxlen)
	{
		perror("Over to limit");
		return -1;
	}

	for(i = 0; i < n; i++)
	{
		scanf("%s %d %d", pstu[i].number, &pstu[i].testbit, &pstu[i].exambit);
	}

	return n;
}
int GetFoundBit(int *pbit, int maxlen)
{
	int m = 0;
	int i = 0;

	scanf("%d", &m);

	if(m > maxlen)
	{
		perror("Over to limit");
		return -1;
	}

	for(i = 0; i < m; i++)
	{
		scanf("%d", &pbit[i]);

	}
	return m;
}

int PrintStudentBit(struct student *pstu, int curlen, int *pfound, int m)
{
	int i = 0;
	int j = 0;

	for(i = 0; i < m; i++)
	{
		for(j = 0; j < curlen; j++)
		{
			if(pstu[j].testbit == pfound[i])
			{
				printf("%s %d\n", pstu[j].number, pstu[j].exambit);
			}
		}
	}
	
	return 0;

}

int main(void)
{
	struct student stu[1000];
	int curlen = 0;
	int bitinfo[1000];
	int foundnum = 0;
	
	curlen = GetStudentBit(stu, 1000);
	foundnum = GetFoundBit(bitinfo, 1000);
	
	PrintStudentBit(stu, curlen, bitinfo, foundnum);

	return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1476133.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Linux】进程优先级以及Linux内核进程调度队列的简要介绍

进程优先级 基本概念查看系统进程修改进程的优先级Linux2.6内核进程调度队列的简要介绍和进程优先级有关的概念进程切换 基本概念 为什么会存在进程优先级&#xff1f;   进程优先级用于确定在资源竞争的情况下&#xff0c;哪个进程将被操作系统调度为下一个运行的进程。进程…

MFC 皮肤库配置

1.创建MFC 对话框 2.添加皮肤资源 添加资源 添加头文件 关闭SDL检测 添加静态库文件 修改字符集 添加头文件 将皮肤中的ssk文件加载到初始化实例中 > 运行即可

十三、Qt多线程与线程安全

一、多线程程序 QThread类提供了管理线程的方法&#xff1a;一个对象管理一个线程一般从QThread继承一个自定义类&#xff0c;重载run函数 1、实现程序 &#xff08;1&#xff09;创建项目&#xff0c;基于QDialog &#xff08;2&#xff09;添加类&#xff0c;修改基于QThr…

计算机网络-网络互连和互联网(四)

1.TCP协议&#xff1a; 传输控制协议&#xff0c;面向字节流按顺序连接&#xff0c;可靠&#xff0c;全双工&#xff0c;可变滑动窗口&#xff0c;缓冲累积传送。协议号为6。下面是TCP段&#xff08;段头&#xff09;&#xff0c;TCP头&#xff08;传输头&#xff09;&#xf…

数学建模【神经网络】

一、神经网络简介 机器学习与神经网络 机器学习是一类实现人工智能的方法总称&#xff0c;让计算机模拟或实现人类的学习行为神经网络是实现机器学习的一种模型实现机器学习的模型还有支持向量机&#xff0c;决策树&#xff0c;朴素贝叶斯分类器等 神经网络能用来做什么 已…

Lyra游戏框架宏观框架梳理

想象一下一个完整游戏流程。 Loading界面。 进入场景。 弹出Menu菜单 加载角色。 角色动画系统-切换动画系统&#xff08;默认-剑客-拳手&#xff09; 角色皮肤切换 相机 角色可以接收到用户输入&#xff0c;然后进行前后左右移动。 角色可以接收到用户输入&#xff0c;…

C语言----联合体

不知道大家是否听说过联合体这个名词。但其实大家不用觉得联合体有多特殊&#xff0c;大家可以想象结构体是一栋楼&#xff0c;里面有很多房间&#xff0c;住了形形色色的住户&#xff08;不用或者相同的数据&#xff09;。但联合体只有一个房间&#xff0c;所有的住户都挤在这…

半小时到秒级,京东零售定时任务优化怎么做的?

导言&#xff1a; 京东零售技术团队通过真实线上案例总结了针对海量数据批处理任务的一些通用优化方法&#xff0c;除了供大家借鉴参考之外&#xff0c;也更希望通过这篇文章呼吁大家在平时开发程序时能够更加注意程序的性能和所消耗的资源&#xff0c;避免在流量突增时给系统…

认证模式~

认证方式 基于Cookie和Session的认证方式 基于Cookie和Session的认证是传统的Web应用认证机制。它依赖于HTTP协议无状态的特性&#xff0c;在客户端&#xff08;浏览器&#xff09;和服务器之间保持用户的状态。 工作原理 用户登录&#xff1a;用户通过输入用户名和密码来登…

【AIGC】OpenAI推出王炸级模型sora,颠覆AI视频行业

文章目录 强烈推荐前言什么是OpenAI Sora&#xff1f;工作原理&#xff1a;算法原理&#xff1a;应用场景展望与其他视频生成模型相比有哪些优势和不足&#xff1f;优点缺点 总结强烈推荐专栏集锦写在最后 强烈推荐 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易…

Unity中字符串拼接0GC方案

本文主要分析C#字符串拼接产生GC的原因&#xff0c;以及介绍名为ZString的库&#xff0c;它可以将字符串生成的内存分配为零。 在C#中&#xff0c;字符串拼接通常有三种方式&#xff1a; 直接使用号连接&#xff1b;string.format;使用StringBuilder&#xff1b; 下面分别细…

table展示子级踩坑

##elemenui中table通过row中是否有children进行判断是否展示子集&#xff0c;通过设置tree-prop的属性进行设置&#xff0c;子级的children的名字可以根据自己的子级名字进行替换&#xff0c;当然同样可以对数据处理成含有chilren的子级list。 问题&#xff1a; 1.如果是根据后…

java大数据开发面试题,完美世界java面试题

02 JVM 线程JVM内存区域JVM运行时内存垃圾回收与算法JAVA四种引用类型GC分代收集算法 VS 分区收集算法GC垃圾收集器JAVA IO/NIOJVM类加载器 03 JAVA集合 接口继承关系和实现LISTSETMAP 04 JAVA多线程并发 JAVA并发知识库JAVA线程实现/创建方式4种线程池线程生命周期&#xf…

★【递归】【链表】Leetcode 21. 合并两个有序链表

★【递归】【链表】Leetcode 21. 合并两个有序链表 解法1 &#xff1a;递归链表 简直是好题啊好题多做做 ---------------&#x1f388;&#x1f388;题目链接&#x1f388;&#x1f388;------------------- 解法1 &#xff1a;递归链表 简直是好题啊好题多做做 >>>…

Time Travel

题目链接 解题思路 由于所有边集中的边加起来的总和至多为&#xff0c;无向图即&#xff0c;可以存下所以直接对所有边集中的边进行建边&#xff0c;同时对于每条边&#xff0c;记录其所在边集号对于每个边集&#xff0c;由大到小维护其能通过的时间点然后从1号跑最短路到当前…

javaWeb个人学习03

事务管理: 概述: 一个事务里面的操作 要么同时成功, 要么同时失败例子: 比如在根据id 删除部门的时候 当部门删除成功了 但是遇到了异常 导致下面的代码没有继续执行下去 就没法根据id删除员工的信息了 这个时候 事务就很重要了 开启回滚 或者提交事务 要么同时成功 要么同时…

【考研数学】《汤家凤 1800 》《张宇 1000 》《李永乐 660 》《李林 880 》应该如何选择?

本人数学逆袭的路上&#xff0c;深知选对一本题集对我的重要性&#xff01;&#xff01;&#xff01; 我本科期间&#xff0c;数学并不是我的强项&#xff0c;但是我却能够在考研的时候靠数学甩开别人几十分成功上岸&#xff0c;一本优秀的题集起到了关键的作用。 1800题&…

MySQL的事务与隔离级别

1. 什么是事务&#xff1f; 数据库中的事务是指对数据库执行一批操作&#xff0c;而这些操作最终要么全部执行成功&#xff0c;要么全部失败&#xff0c;不会存在部分成功的情况。这个时候就需要用到事务。 最经典的例子就是转账&#xff0c;你要给朋友小白转 1000 块钱&…

选择排序,冒泡排序,插入排序,快速排序及其优化

目录 1 选择排序 1.1 原理 1.2 具体步骤 1.3 代码实现 1.4 优化 2 冒泡排序 2.1 原理 2.2 具体步骤 2.3 代码实现 2.4 优化 3 插入排序 3.1 原理 3.2 具体步骤 3.3 代码实现 3.4 优化 4. 快速排序 4.1 原理 4.2 具体步骤 4.3 代码实现 4.4 优化 为了讲…

如何优化一个看似正常的数据库

通常DBA是不会太了解业务逻辑的&#xff0c;遇到系统中劣质的sql 一般也是以通过添加索引的方式来优化&#xff0c;但是并不是所有的sql都能通过添加索引来优化 这就需要重sql的本身来做分析&#xff0c;另外还要了解什么样的语句会不走索引&#xff01;本文通过几个简单的例子…