操作系统C语言实现07---并发

1.介绍

并发是现代计算中的一个基本概念,其中多个任务或进程同时执行。在并行和分布式系统的世界中,理解并发对于开发高效可靠的软件至关重要。
在这里插入图片描述

竞态条件(Race Conditions)

当系统的行为依赖于事件的相对时间时,就会出现竞争条件,特别是在并发系统中。当多个线程或进程在没有适当同步的情况下访问共享资源时,就会发生这种情况,从而导致不可预测和可能不正确的结果。
特征:

  • 多个线程访问共享资源
  • 缺乏适当的同步机制
  • 执行顺序会影响最终结果
    类型:
  1. 读-修改-写竞态条件
    在这种类型中,多个线程读取共享变量,修改它,并回写结果,可能会覆盖彼此的修改。
  2. 检查-行动竞态条件
    线程检查条件,然后根据该条件采取操作,在检查和操作之间可能会发生变化。
  3. 复合竞态条件
    涉及多个共享资源和线程之间复杂交互的复杂场景。

预防措施

  1. 互斥(Mutex)
    使用锁来确保一次只有一个线程可以访问临界区,用于提供对共享资源的独占访问。可以把互斥锁看作是一个数字锁,它确保在任何给定时刻只有一个线程可以进入代码的临界区。该机制防止多个线程同时修改共享数据,这可能导致不一致或损坏的状态。。
  2. 原子操作(Atomic Operations)
    利用编程语言和硬件提供的原子指令。
  3. 同步原语(Synchronization Primitives)
  • 信号量
    信号量维护一个表示可用资源数量的内部计数器。线程可以对信号量执行两种主要操作:等待(减少计数器)和发出信号(增加计数器)。当信号量的计数器达到零时,试图获取信号量的后续线程将被阻塞,直到资源可用为止。
    有两种主要类型的信号量:二进制信号量和计数信号量。二进制信号量的功能类似于互斥锁,只允许两种状态——锁定和解锁。
  • 条件变量
  • 读写锁

代码例子:

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

int shared_counter = 0;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

// Race Condition Version
void* increment_without_mutex(void* arg) {
    for (int i = 0; i < 100000; i++) {
        shared_counter++;  // Unsafe increment
    }
    return NULL;
}

// Safe Synchronized Version
void* increment_with_mutex(void* arg) {
    for (int i = 0; i < 100000; i++) {
        pthread_mutex_lock(&mutex);
        shared_counter++;  // Safe increment
        pthread_mutex_unlock(&mutex);
    }
    return NULL;
}

int main() {
    pthread_t threads[2];

    // Demonstrate Race Condition
    printf("Demonstrating Race Condition:\n");
    shared_counter = 0;
    for (int i = 0; i < 2; i++) {
        pthread_create(&threads[i], NULL, increment_without_mutex, NULL);
    }
    
    for (int i = 0; i < 2; i++) {
        pthread_join(threads[i], NULL);
    }
    printf("Final Counter (Unsafe): %d\n", shared_counter);

    // Demonstrate Safe Synchronization
    printf("\nDemonstrating Safe Synchronization:\n");
    shared_counter = 0;
    for (int i = 0; i < 2; i++) {
        pthread_create(&threads[i], NULL, increment_with_mutex, NULL);
    }
    
    for (int i = 0; i < 2; i++) {
        pthread_join(threads[i], NULL);
    }
    printf("Final Counter (Safe): %d\n", shared_counter);

    return 0;
}

2.同步(Synchronization)

同步是并发编程的基础,它代表了一种复杂的机制,可以确保多个线程或进程之间有序且可预测的交互。在复杂的现代计算环境中,并行处理已成为常态,同步技术为管理共享资源、防止数据竞争和维护系统完整性提供了关键框架。当多个线程试图执行,同步的核心是解决在多线程环境中协调对共享资源的访问。
在这里插入图片描述

死锁(Deadlock)

死锁的特征有四个基本条件,它们必须同时存在才能发生死锁。这些条件首先由计算机科学先驱提出,为理解和防止这些复杂的同步故障提供了一个框架。

  1. 涉及互斥。 即资源不能同时被多个线程共享。这意味着,当一个资源被分配给一个线程时,在显式释放之前,其他线程将无法使用该资源。虽然互斥对于维护数据完整性至关重要,但它也可能造成资源争用。
  2. 保持和等待场景。 在这种情况下,当前持有一个资源的线程同时请求额外的资源。如果这些额外的资源已经分配给其他线程,则请求线程在保留其初始资源的同时进入等待状态。这就产生了可能导致系统锁定的潜在循环依赖。
  3. 没有抢占。 在没有抢占的系统中,不能从当前持有资源的线程强制检索资源。一旦资源被分配,它将一直留在线程中,直到该线程主动释放它。这个特性防止了资源分配中的外部干预,从而可能导致死锁情况无限期地持续下去。
  4. 涉及循环等待。 一组线程在循环链中等待彼此持有的资源。想象一下这样一个场景:线程a持有资源X并想要资源Y,线程B持有资源Y并想要资源Z,线程C持有资源Z但想要资源X。这种循环依赖创造了一个完美的死锁场景,没有可能解决。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值