【嵌入式开发-多线程同步】

基本概念

在程序中一些任务需要多个线程来完成,不同的线程之间存在相互制约关系。为了协调线程之间的制约关系引入了线程同步的概念(线程间的通信主要是用于线程同步,所以线程没有进程通信中用于数据交换的通信机制)。线程同步是指按特定的机制(如锁 信号量)来控制线程之间的执行顺序。如果没有线程同步,那线程之间将是无序的。
线程同步的核心思想就是在访问临界区的时候只允许一个或一类线程访问

临界区

多个线程访问或操作同一块区域(代码),这块就称为临界区。

同步机制

嵌入式多线程中主要有三种同步机制:互斥锁、信号量、条件量。

互斥锁

互斥锁用来保证同一时间只有一个线程在执行某段代码(临界区)

互斥锁主要包括下面的基本函数
互斥锁初始化:pthread_mutex_init()
互斥锁上锁:pthread_mutex_lock()
互斥锁判断上锁:pthread_mutex_trylock()
互斥锁解锁:pthread_mutex_unlock()
消除互斥锁:pthread_mutex_destroy()

信号量

多线程中也可以使用信号量来进行数据同步

  1. 信号量初始化
    int sem_init (sem_t *sem , int pshared, unsigned int value);
    对sem指定的信号量进行初始化,设置好共享选项(linux 只支持为0 即表示它是当前进程的局部变量),然后给它一个初始化值VALUE
  2. 等待信号量
    int sem_wait(sem_t *sem);
    给信号量减1.然后等待知道信号量的值大于0
  3. 释放信号量
    int sem_post(sem_t *sem);
    信号量值加1,并通知其他等待线程
  4. 销毁信号量
    int sem_destroy(sem_t *sem);

程序实例:
使用生产者 消费者的经典例子,生产者,消费者共用一个缓冲区,缓冲区存放多条消息。使用信号量如下:

#include<stdio.h>
#include<stdlib.h>
#include<pthread.h>
#include<semaphore.h>

static char buff[50];
pthread_mutex_t mutex;
pthread_mutex_t cond_mutex;
sem_t msg_cnt; //缓冲区消息数
sem_t idle_cnt // 缓冲区空闲数

void consumItem(cahr *buff)
{
	printf("This is a consum item\n");
}
void produceItem(char *buff)
{
    printf("This is a produce item\n");
}

void *consumer(void *param)
{
    while (1)
    {
        sem_wait(&msg_cnt);
        pthread_mutex_lock(&mutex);
        consumeItem(buff);
        pthread_mutex_unlock(&mutex);
        sem_post(&idle_cnt);
    }
    return NULL;
}

void *producer(void *param)
{
    while (1)
    {
        sem_wait(&idle_cnt);
        pthread_mutex_lock(&mutex);
        produceItem(buff);        
        pthread_mutex_unlock(&mutex);
        sem_post(&msg_cnt);
        
    }
    return NULL;
}
 
int main()
{
    pthread_t tid_c, tid_p;
    void *retval;
    pthread_mutex_init(&mutex, NULL);
    pthread_mutex_init(&cond_mutex, NULL);
    
    pthread_cond_t cond;
    pthread_cond_init(&cond, NULL);
 
    sem_init(&msg_cnt, 0, 0);        //初始缓冲区没有消息
    sem_init(&idle_cnt, 0, 10);  //初始缓冲区能放10条消息
    
    pthread_create(&tid_p, NULL, producer, NULL);
    pthread_create(&tid_c, NULL, consumer, NULL);
    
        
    pthread_join(tid_p, &retval);
    pthread_join(tid_c, &retval);
            
    return 0;
}

条件变量

与互斥锁不同,条件变量是用来等待而不是用来上锁的。条件变量用来自动阻塞一个线程,直到某特殊情况发生为止。通常条件变量和互斥锁同时使用。条件变量分 为两部分: 条件和变量。条件本身是由互斥量保护的。线程在改变条件状态前先要锁住互斥量。条件变量使我们可以睡眠等待某种条件出现。条件变量是利用线程间共享的全局 变量进行同步的一种机制,主要包括两个动作:一个线程等待"条件变量的条件成立"而挂起;另一个线程使"条件成立"(给出条件成立信号)。条件的检测是在 互斥锁的保护下进行的。如果一个条件为假,一个线程自动阻塞,并释放等待状态改变的互斥锁。如果另一个线程改变了条件,它发信号给关联的条件变量,唤醒一个或多个等待它的线程,重新获得互斥锁,重新评价条件。如果两进程共享可读写的内存,条件变量可以被用来实现这两进程间的线程同步。

条件变量用来阻塞线程等待某个事件的发生,并且当等待的事件发生时,阻塞线程会被通知。互斥锁的缺点是只有两种状态:锁定和非锁定。而条件变量通过允许线程阻塞和等待另一个线程发送信号的方法弥补了互斥锁的不足,常和互斥锁一起使用。使用时,条件变量被用来阻塞一个线程,当条件不满足时,线程往往解开相应的互斥锁并等待条件发生变化。一旦其它的某个线程改变了条件变量,它将通知相应的条件变量唤醒一个或多个正被此条件变量阻塞的线程。这些线程将重新锁定互斥锁并重新测试条件是否满足。一般说来,条件变量被用来进行线承间的同步

  1. 初始化条件变量
    静态初始化 prthead_cond_t cond = PTHREAD_COND_INITIALER
    动态初始化:ead_cond_init(pthread_cond_t *cond, pthread_condattr_t *cond_attr);
  2. 等待条件成立
    释放锁,同时阻塞等待条件变量为真才行。timewait()设置等待时间,仍未signal,返回ETIMEOUT(加锁保证只有一个线程wait)
    int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
    int thread_cond_timewait(pthread_cond_t *cond,pthread_mutex *mutex,const timespec *abstime);
  3. 激活条件变量
    int pthread_cond_signal(pthread_cond_t *cond);
    int pthread_cond_broadcast(pthread_cond_t *cond); 解除所有线程的阻塞
  4. 清除条件变量
    无线程等待,否则返回EBUSY
    int pthread_cond_destroy(pthread_cond_t *cond);
  5. 程序实例
    本实例使用条件变量实现生产者、消费者的经典例子,生产者、消费者公用一个缓冲区,缓冲区存放多条消息,有多个消费者。如果都使用互斥锁,那么多个消费者线程都要不断的去查看缓冲区是否有消息,有就取走。如果我们用条件变量,多个消费者线程都可以放心的“睡觉”,缓冲区有消息,消费者会收到通知,进而收取消息就行。
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <sys/time.h>
 
static char buff[50];
pthread_mutex_t mutex;
pthread_mutex_t cond_mutex;
pthread_cond_t cond;
 
void consumeItem(char *buff)
{
    printf("This is a consumer item\n");
}
void produceItem(char *buff)
{
    printf("This is a produce item\n");
}
void *consumer(void *param)
{
    int t = *(int *)param;
    while (1)
    {
        pthread_cond_wait(&cond, &cond_mutex);
        pthread_mutex_lock(&mutex);
        printf("consumer thread %d: ", t);
        consumeItem(buff);
        pthread_mutex_unlock(&mutex);
    }
    return NULL;
}
 
void *producer(void *param)
{
    while (1)
    {
        pthread_mutex_lock(&mutex);
        produceItem(buff);        
        pthread_mutex_unlock(&mutex);
        pthread_cond_signal(&cond);
        sleep(1);
    }
    return NULL;
}
 
int main(int argc, char **argv)
{
    pthread_t tid_c1, tid_p, tid_c2, tid_c3;
    void *retval;
    pthread_mutex_init(&mutex, NULL);
    pthread_mutex_init(&cond_mutex, NULL);
    
    pthread_cond_t cond;
    pthread_cond_init(&cond, NULL);
    
    
    int p[3] = {1, 2, 3}; //线程编号
    pthread_create(&tid_p, NULL, producer, NULL);
    pthread_create(&tid_c1, NULL, consumer, &p[0]);
    pthread_create(&tid_c2, NULL, consumer, &p[1]);
    pthread_create(&tid_c3, NULL, consumer, &p[2]);
 
    
    pthread_join(tid_p, &retval);
    pthread_join(tid_c1, &retval);
    pthread_join(tid_c2, &retval);
    pthread_join(tid_c3, &retval);
        
    return 0;
}

转载:
[1]: https://blog.51cto.com/quantfabric/1827303

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
水资源是人类社会的宝贵财富,在生活、工农业生产中是不可缺少的。随着世界人口的增长及工农业生产的发展,需水量也在日益增长,水已经变得比以往任何时候都要珍贵。但是,由于人类的生产和生活,导致水体的污染,水质恶化,使有限的水资源更加紧张。长期以来,油类物质(石油类物质和动植物油)一直是水和土壤中的重要污染源。它不仅对人的身体健康带来极大危害,而且使水质恶化,严重破坏水体生态平衡。因此各国都加强了油类物质对水体和土壤的污染的治理。对于水中油含量的检测,我国处于落后阶段,与国际先进水平存在差距,所以难以满足当今技术水平的要求。为了取得具有代表性的正确数据,使分析数据具有与现代测试技术水平相应的准确性和先进性,不断提高分析成果的可比性和应用效果,检测的方法和仪器是非常重要的。只有保证了这两方面才能保证快速和准确地测量出水中油类污染物含量,以达到保护和治理水污染的目的。开展水中油污染检测方法、技术和检测设备的研究,是提高水污染检测的一条重要措施。通过本课题的研究,探索出一套适合我国国情的水质污染现场检测技术和检测设备,具有广泛的应用前景和科学研究价值。 本课题针对我国水体的油污染,探索一套检测油污染的可行方案和方法,利用非分散红外光度法技术,开发研制具有自主知识产权的适合国情的适于野外便携的测油仪。利用此仪器,可以检测出被测水样中亚甲基、甲基物质和动植物油脂的污染物含量,为我国众多的环境检测站点监测水体的油污染状况提供依据。
### 内容概要 《计算机试卷1》是一份综合性的计算机基础和应用测试卷,涵盖了计算机硬件、软件、操作系统、网络、多媒体技术等多个领域的知识点。试卷包括单选题和操作应用两大类,单选题部分测试学生对计算机基础知识的掌握,操作应用部分则评估学生对计算机应用软件的实际操作能力。 ### 适用人群 本试卷适用于: - 计算机专业或信息技术相关专业的学生,用于课程学习或考试复习。 - 准备计算机等级考试或职业资格认证的人士,作为实战演练材料。 - 对计算机操作有兴趣的自学者,用于提升个人计算机应用技能。 - 计算机基础教育工作者,作为教学资源或出题参考。 ### 使用场景及目标 1. **学习评估**:作为学校或教育机构对学生计算机基础知识和应用技能的评估工具。 2. **自学测试**:供个人自学者检验自己对计算机知识的掌握程度和操作熟练度。 3. **职业发展**:帮助职场人士通过实际操作练习,提升计算机应用能力,增强工作竞争力。 4. **教学资源**:教师可以用于课堂教学,作为教学内容的补充或学生的课后练习。 5. **竞赛准备**:适合准备计算机相关竞赛的学生,作为强化训练和技能检测的材料。 试卷的目标是通过系统性的题目设计,帮助学生全面复习和巩固计算机基础知识,同时通过实际操作题目,提高学生解决实际问题的能力。通过本试卷的学习与练习,学生将能够更加深入地理解计算机的工作原理,掌握常用软件的使用方法,为未来的学术或职业生涯打下坚实的基础。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值