Linux多线程同步机制——读写锁(Read-WriteLock)

原创 Linux二进制 2024-07-08 12:28

概述

读写锁(Read-Write Lock)是一种线程同步机制,用于管理对共享资源的访问。与互斥锁(Mutex)不同,读写锁允许多个线程同时以读模式访问共享资源,但只允许一个线程以写模式访问资源。这种机制特别适用于读操作远多于写操作的场景,可以显著提高程序的并发性能。

读写锁原理

读写锁的设计基于以下原则:

  • 读操作共享:允许多个读线程同时访问共享资源,只要没有写线程正在访问或等待访问资源。
  • 写操作排他:在任何时候,只允许一个写线程访问共享资源。在写线程持有锁期间,所有的读线程和写线程都将被阻塞。

读写锁内部实现机制

读写锁的内部实现通常依赖于一个或多个底层锁和一些额外的状态信息。以下是一种常见的实现方式:

  • 计数器:用于跟踪当前有多少读线程正在持有读锁。通常,当计数器大于 0 时,表示有读线程正在访问资源,此时不允许写线程获取锁;当计数器为 0 时,表示没有读线程持有锁,写线程可以尝试获取锁。

  • 写锁标志:用于标记是否有写线程正在持有锁或者有写线程正在等待获取锁。当写锁标志为真时,所有读线程和写线程都将被阻塞,直到写线程释放锁。

  • 底层互斥锁和条件变量:读写锁通常会使用一个互斥锁来保护其内部状态(如计数器和写锁标志),以及一个或多个条件变量来实现线程间的等待和唤醒机制。

读写锁的典型实现

在 Linux 和 POSIX 兼容的系统中,读写锁通常通过 pthread_rwlock_t 类型实现。其内部可能包含如下组件:

  • 互斥锁(Mutex):用于保护读写锁的内部状态,如读计数器和写锁状态。
  • 读计数器(Read Counter):记录当前持有读锁的线程数量。
  • 条件变量(Condition Variable):用于实现线程的等待和通知机制。通常,会有两个条件变量,一个用于读线程,一个用于写线程。

当线程尝试获取读锁时,它会检查写锁状态和读计数器,如果当前没有写线程正在访问资源,则增加读计数器并允许读线程继续;如果存在写操作,则读线程将被阻塞,直到写操作完成。

类似地,当线程尝试获取写锁时,它会检查读计数器和写锁状态。如果当前没有读线程和写线程正在访问资源,则设置写锁状态并允许写线程继续;如果有读线程或写线程正在访问资源,则写线程将被阻塞,直到所有读线程和前一个写线程完成操作。

读写锁相关API

当然,我会补充完整上面的程序,并进一步完善API函数的描述。请注意,由于程序中的线程是无限循环的,为了示例的完整性,我将添加一个全局变量作为退出条件。此外,我将更详细地解释API函数的使用。

pthread_rwlock_init -- 初始化读写锁

int pthread_rwlock_init(pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attr);
  • 参数
    • rwlock:指向要初始化的读写锁变量的指针。
    • attr:(可选)指向读写锁属性的指针。如果传递NULL,则使用默认属性。
  • 返回值:成功时返回0,失败时返回错误码。

pthread_rwlock_destroy -- 销毁读写锁

int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);
  • 参数
    • rwlock:指向要销毁的读写锁变量的指针。
  • 返回值:成功时返回0,失败时返回错误码。

pthread_rwlock_rdlock -- 加读锁

int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
  • 参数
    • rwlock:指向读写锁变量的指针。
  • 返回值:成功时返回0,失败时返回错误码。如果锁被其他线程以写模式持有,则调用线程将被阻塞。

pthread_rwlock_wrlock -- 加写锁

int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
  • 参数
    • rwlock:指向读写锁变量的指针。
  • 返回值:成功时返回0,失败时返回错误码。如果锁被其他线程以读模式或写模式持有,则调用线程将被阻塞。

pthread_rwlock_tryrdlock -- 尝试加读锁(非阻塞)

int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);
  • 参数
    • rwlock:指向读写锁变量的指针。
  • 返回值:成功时返回0,如果锁不可用,则返回EBUSY

C 语言实现读写锁

1、封装POSIX 线程库的读写锁

封装 POSIX 线程库提供的pthread_rwlock_t类型的读写锁,以及相关的操作函数pthread_rwlock_rdlockpthread_rwlock_wrlock等,即可实现简单的读写锁,无需自行实现复杂的逻辑。以下是一个简单的 C 语言实现读写锁的代码:

#include 
#include 
#include 
#include 

// 定义读写锁结构体
typedef struct {
    pthread_rwlock_t rwlock; // 使用 POSIX 的读写锁
rwlock_t;

// 定义线程参数结构体
typedef struct thread_params {
    rwlock_t *lock;
    int id; // 线程标识符
thread_params_t;

// 初始化读写锁
void rwlock_init(rwlock_t *lock) {
    pthread_rwlock_init(&lock->rwlock, NULL);
}

// 销毁读写锁并释放资源
void rwlock_destroy(rwlock_t *lock) {
    pthread_rwlock_destroy(&lock->rwlock);
}

// 获取读锁
void rwlock_read_lock(rwlock_t *lock) {
    pthread_rwlock_rdlock(&lock->rwlock);
}

// 释放读锁
void rwlock_read_unlock(rwlock_t *lock) {
    pthread_rwlock_unlock(&lock->rwlock);
}

// 获取写锁
void rwlock_write_lock(rwlock_t *lock) {
    pthread_rwlock_wrlock(&lock->rwlock);
}

// 释放写锁
void rwlock_write_unlock(rwlock_t *lock) {
    pthread_rwlock_unlock(&lock->rwlock);
}

// 读者线程函数
void *reader(void *arg) {
    thread_params_t *params = arg; // 从参数中获取线程参数结构体
    int i;
    for (i = 0; i < 3; i++) {
        rwlock_read_lock(params->lock);
        printf("读者线程 %d: 正在读取...\n", params->id);
        usleep(100000);
        rwlock_read_unlock(params->lock);
    }
    return NULL;
}

// 写者线程函数
void *writer(void *arg) {
    thread_params_t *params = arg; // 从参数中获取线程参数结构体
    int i;
    for (i = 0; i < 5; i++) {
        rwlock_write_lock(params->lock);
        printf("写者线程 %d: 正在写入...\n", params->id);
        usleep(500000);
        rwlock_write_unlock(params->lock);
    }
    return NULL;
}

int main() {
    rwlock_t lock;
    rwlock_init(&lock);

    pthread_t threads[5];
    thread_params_t thread_params[5]; // 定义线程参数数组

    int i;

    // 初始化线程参数数组
    for (i = 0; i < 5; i++) {
        thread_params[i].lock = &lock;
        thread_params[i].id = i + 1// 分配线程标识符
    }

    // 创建读者线程
    for (i = 0; i < 4; i++) {
        pthread_create(&threads[i], NULL, reader, &thread_params[i]);
    }

    // 创建写者线程
    pthread_create(&threads[4], NULL, writer, &thread_params[4]);

    // 加入所有线程,等待它们完成
    for (i = 0; i < 5; i++) {
        pthread_join(threads[i], NULL);
    }

    rwlock_destroy(&lock);

    return 0;
}

注意:封装 rwlock_t 结构体的主要原因在于提供一个清晰、模块化的接口来管理和使用读写锁,这带来了以下几方面的优势:

  1. 封装细节:

  • 将读写锁的实现细节封装在rwlock_t结构体内,对外只暴露必要的接口(如初始化、销毁、读锁和写锁操作)。这样做的好处是隐藏了内部实现的复杂性,外部调用者只需要关注如何使用锁,而不必关心锁的具体实现。
  • 类型安全:

    • 使用专门的结构体类型rwlock_t来表示读写锁,增强了类型安全。这意味着在使用读写锁的地方,编译器可以检查是否正确使用了读写锁相关的函数,避免了类型错误。
  • 可扩展性:

    • 如果将来需要改变读写锁的实现方式,比如从使用pthread_rwlock_t切换到另一种锁机制,只需修改rwlock_t结构体和相关操作函数,而无需修改所有使用读写锁的地方。这大大提高了代码的可维护性和可扩展性。
  • 代码组织与重用:

    • 封装读写锁的操作在一个独立的结构体和一组函数中,使得代码更加整洁、有条理。此外,这样的封装有利于代码的重用,如果项目中其他地方也需要使用读写锁,可以直接引用rwlock_t及相关函数,无需重复编写相同的代码。
  • 测试与调试便利性:

    • 将读写锁的创建、使用和销毁操作集中在一个结构体及其相关函数中,方便了单元测试和调试。可以独立地测试读写锁的功能,确保其在各种情况下的正确性。

    综上所述,封装rwlock_t结构体是软件工程中一种常见的抽象和封装机制,它不仅提高了代码的可读性和可维护性,也增强了系统的灵活性和健壮性。

    这个示例中的关键点详细阐述如下:

    1. 读写锁结构体定义 (rwlock_t)

    • 定义:

      typedef struct {
          pthread_rwlock_t rwlock; // 使用 POSIX 的读写锁
      rwlock_t;
    • 解析:

      • rwlock_t结构体封装了一个pthread_rwlock_t类型的读写锁实例。
      • pthread_rwlock_t 是 POSIX 标准中定义的一种高级锁机制,允许同时存在多个读操作,但写操作是排他的,确保了数据在并发访问时的一致性。

    2. 线程参数结构体定义 (thread_params_t)

    • 定义:

      typedef struct thread_params {
          rwlock_t *lock;
          int id; // 线程标识符
      thread_params_t;
    • 解析:

      • thread_params_t 结构体用于存储线程运行所需的信息,包括指向读写锁的指针和线程的唯一标识符。
      • 这种设计允许线程函数以统一的方式接收参数,增强代码的可读性和可维护性。

    3. 读写锁操作函数

    • 初始化与销毁:

      void rwlock_init(rwlock_t *lock);
      void rwlock_destroy(rwlock_t *lock);
      • rwlock_init 负责初始化读写锁,确保其处于可用状态。
      • rwlock_destroy 用于清理锁资源,避免内存泄漏。
      • 解析:
    • 读锁操作:

      void rwlock_read_lock(rwlock_t *lock);
      void rwlock_read_unlock(rwlock_t *lock);
      • rwlock_read_lock 获取读锁,允许多个读线程同时访问共享资源。
      • rwlock_read_unlock 释放读锁,使其他线程有机会获取锁。
      • 解析:
    • 写锁操作:

      void rwlock_write_lock(rwlock_t *lock);
      void rwlock_write_unlock(rwlock_t *lock);
      • rwlock_write_lock 获取写锁,确保写操作的排他性,防止数据竞争。
      • rwlock_write_unlock 释放写锁,使其他线程可以继续执行。
      • 解析:

    4. 线程函数

    • 读者线程:

      void *reader(void *arg);
      • 读者线程函数 reader 接收一个 thread_params_t 类型的参数,从中提取读写锁和线程标识符。
      • 线程执行多次读操作,每次读取前获取读锁,读取后释放读锁。
      • 解析:
    • 写者线程:

      void *writer(void *arg);
      • 写者线程函数 writer 同样接收 thread_params_t 类型的参数。
      • 线程执行多次写操作,每次写入前获取写锁,写入后释放写锁。
      • 解析:

    5. 主函数 (main)

    • 初始化与线程创建:
      • 初始化读写锁。
      • 创建线程参数数组,为每个线程分配唯一标识符和读写锁引用。
      • 使用pthread_create 创建 4 个读者线程和 1 个写者线程。
    • 线程同步与资源清理:
      • 使用 pthread_join 确保所有线程完成后再继续执行。
      • 调用 rwlock_destroy 销毁读写锁,释放相关资源。

    6. 线程标识符

    • 功能:
      • 每个线程拥有一个从 1 开始的唯一标识符,便于在日志和调试信息中区分不同线程。

    7. POSIX读写锁机制

    • 优势:
      • 支持多个读线程的同时访问,提高了读密集型应用的并发性能。
      • 确保写操作的排他性,避免数据损坏,适用于写操作较少的场景。

    8. 线程创建与管理

    • 细节:
      • 使用pthread_create创建线程,传入线程函数和参数。
      • 利用pthread_join等待线程结束,保证程序的正确性和资源的有序释放。

    9. 资源管理

    • 重要性:
      • 通过初始化和销毁读写锁,确保了锁资源的生命周期管理,避免了内存泄漏和资源浪费。

    编译并执行程序,结果如下:

    [root@localhost rwlock]# gcc pthread_rwlock.c -o pthread_rwlock -lpthread
    [root@localhost rwlock]# ls
    pthread_rwlock pthread_rwlock.c
    [root@localhost rwlock]# ./pthread_rwlock
    读者线程 1: 正在读取...
    读者线程 2: 正在读取...
    读者线程 3: 正在读取...
    读者线程 4: 正在读取...
    读者线程 1: 正在读取...
    读者线程 2: 正在读取...
    读者线程 4: 正在读取...
    读者线程 3: 正在读取...
    读者线程 1: 正在读取...
    读者线程 2: 正在读取...
    读者线程 4: 正在读取...
    读者线程 3: 正在读取...
    写者线程 5: 正在写入...
    写者线程 5: 正在写入...
    写者线程 5: 正在写入...
    写者线程 5: 正在写入...
    写者线程 5: 正在写入...

    通过深入解析上述代码和结果,我们可以更全面地理解基于 POSIX 读写锁的多线程程序设计策略,以及如何有效利用锁机制来提高并发应用的性能和可靠性。

    2、自定义实现的典型读写锁

    自定义实现读写锁代码需要开发者更深入地理解读写锁的底层实现原理。完全自行实现读写锁的逻辑,通过互斥锁、条件变量以及自定义的读计数和写标志来管理读写操作的同步。以下是一段 C 语言实现自定义实现读写锁的代码:

    #include 
    #include 

    // 定义读写锁结构体
    typedef struct rwlock {
        pthread_mutex_t lock;  // 互斥锁,用于保护读写锁的内部状态
        pthread_cond_t read_cond;  // 条件变量,用于读操作的等待和通知
        pthread_cond_t write_cond;  // 条件变量,用于写操作的等待和通知
        int read_count;  // 读操作的计数
        int write_in_progress;  // 写操作是否正在进行的标志
    rwlock_t;

    // 初始化读写锁
    void rwlock_init(rwlock_t *rwlock) {
        // 初始化互斥锁
        pthread_mutex_init(&rwlock->lock, NULL);
        // 初始化读操作的条件变量
        pthread_cond_init(&rwlock->read_cond, NULL);
        // 初始化写操作的条件变量
        pthread_cond_init(&rwlock->write_cond, NULL);
        // 初始时读计数为 0
        rwlock->read_count = 0;
        // 初始时写操作未进行
        rwlock->write_in_progress = 0;
    }

    // 读锁加锁
    void rwlock_read_lock(rwlock_t *rwlock) {
        // 获取互斥锁
        pthread_mutex_lock(&rwlock->lock);
        // 若有写操作正在进行,读线程等待
        while (rwlock->write_in_progress) {
            pthread_cond_wait(&rwlock->read_cond, &rwlock->lock);
        }
        // 读计数增加
        rwlock->read_count++;
        // 释放互斥锁
        pthread_mutex_unlock(&rwlock->lock);
    }

    // 读锁解锁
    void rwlock_read_unlock(rwlock_t *rwlock) {
        // 获取互斥锁
        pthread_mutex_lock(&rwlock->lock);
        // 读计数减少
        rwlock->read_count--;
        // 若读计数为 0 且无写操作正在进行,通知写线程
        if (rwlock->read_count == 0 && rwlock->write_in_progress == 0) {
            pthread_cond_signal(&rwlock->write_cond);
        }
        // 释放互斥锁
        pthread_mutex_unlock(&rwlock->lock);
    }

    // 写锁加锁
    void rwlock_write_lock(rwlock_t *rwlock) {
        // 获取互斥锁
        pthread_mutex_lock(&rwlock->lock);
        // 若有读操作或写操作正在进行,写线程等待
        while (rwlock->read_count > 0 || rwlock->write_in_progress) {
            pthread_cond_wait(&rwlock->write_cond, &rwlock->lock);
        }
        // 标记写操作正在进行
        rwlock->write_in_progress = 1;
        // 释放互斥锁
        pthread_mutex_unlock(&rwlock->lock);
    }

    // 写锁解锁
    void rwlock_write_unlock(rwlock_t *rwlock) {
        // 获取互斥锁
        pthread_mutex_lock(&rwlock->lock);
        // 标记写操作结束
        rwlock->write_in_progress = 0;
        // 通知所有等待读的线程
        pthread_cond_broadcast(&rwlock->read_cond);
        // 通知等待写的线程
        pthread_cond_signal(&rwlock->write_cond);
        // 释放互斥锁
        pthread_mutex_unlock(&rwlock->lock);
    }

    // 读线程的操作函数
    void reader_function(rwlock_t *rwlock) {
        rwlock_read_lock(rwlock);
        printf("Reader is reading...\n");
        rwlock_read_unlock(rwlock);
    }

    // 写线程的操作函数
    void writer_function(rwlock_t *rwlock) {
        rwlock_write_lock(rwlock);
        printf("Writer is writing...\n");
        rwlock_write_unlock(rwlock);
    }

    int main() {
        rwlock_t rwlock;  // 定义读写锁变量
        rwlock_init(&rwlock);  // 初始化读写锁

        pthread_t reader1, reader2, writer;  // 定义线程变量

        // 创建读线程 1
        pthread_create(&reader1, NULL, (void *)reader_function, &rwlock);
        // 创建读线程 2
        pthread_create(&reader2, NULL, (void *)reader_function, &rwlock);
        // 创建写线程
        pthread_create(&writer, NULL, (void *)writer_function, &rwlock);

        // 等待读线程 1 结束
        pthread_join(reader1, NULL);
        // 等待读线程 2 结束
        pthread_join(reader2, NULL);
        // 等待写线程结束
        pthread_join(writer, NULL);

        return 0;
    }

    以下是对这段代码的详细解析:

    1. 包含头文件
    • #include :包含了 POSIX 线程库的头文件,用于多线程编程。
    • #include :包含了标准输入输出头文件,用于打印输出。
  • 定义读写锁结构体 rwlock_t
    • pthread_mutex_t lock:用于保护读写锁内部状态的互斥锁。
    • pthread_cond_t read_cond:用于读操作等待和通知的条件变量。
    • pthread_cond_t write_cond:用于写操作等待和通知的条件变量。
    • int read_count:记录读操作的数量。
    • int write_in_progress:标志是否有写操作正在进行。
  • 函数定义
    • rwlock_init 函数:初始化读写锁的各个成员,包括互斥锁和条件变量,将读计数设为0,写标志设为0
    • rwlock_read_lock 函数:获取读锁。先获取互斥锁,若有写操作正在进行则等待,然后增加读计数,最后释放互斥锁。
    • rwlock_read_unlock 函数:释放读锁。先获取互斥锁,减少读计数,若读计数为 0 且无写操作正在进行则通知写线程,最后释放互斥锁。
    • rwlock_write_lock 函数:获取写锁。先获取互斥锁,若有读操作或写操作正在进行则等待,然后设置写标志为 1,最后释放互斥锁。
    • rwlock_write_unlock 函数:释放写锁。先获取互斥锁,清除写标志,通知所有等待读的线程和一个等待写的线程,最后释放互斥锁。
    • reader_function 函数:读线程的执行函数,获取读锁后打印信息然后释放读锁。
    • writer_function 函数:写线程的执行函数,获取写锁后打印信息然后释放写锁。
  • main 函数
    • 定义读写锁变量 rwlock 并初始化。
    • 定义线程变量 reader1reader2 和 writer
    • 创建两个读线程和一个写线程,并分别指定执行函数和传递读写锁参数。
    • 使用 pthread_join 等待三个线程结束,确保程序不会提前退出。总的来说,这段代码实现了一个简单的读写锁机制,通过多线程的方式展示了读线程和写线程对共享资源的同步访问。

    编译并执行程序,结果如下:

    [root@localhost rwlock]# gcc pthread_rwlock_st.c -o pthread_rwlock_st -lpthread
    [root@localhost rwlock]# ls
    pthread_rwlock pthread_rwlock.c pthread_rwlock_st pthread_rwlock_st.c
    [root@localhost rwlock]# ./pthread_rwlock_st
    Reader is reading...
    Reader is reading...
    Writer is writing...

    总结

    读写锁相比于传统的互斥锁(mutex)具有更高的并发性能,特别是在读操作远多于写操作的场景下。这是因为读写锁允许多个读线程同时访问共享资源,从而减少了线程间的等待时间,提高了系统的整体吞吐量。

    然而,读写锁也有其局限性,例如在写操作频繁的场景下,由于写操作的排他性,可能会导致大量的读线程被阻塞,降低系统的并发性能。因此,在设计多线程应用时,选择合适的同步机制是非常重要的。


    Linux二进制 Linux编程、内核模块、网络原创文章分享,欢迎关注"Linux二进制"微信公众号
    评论
    • 嘿,咱来聊聊RISC-V MCU技术哈。 这RISC-V MCU技术呢,简单来说就是基于一个叫RISC-V的指令集架构做出的微控制器技术。RISC-V这个啊,2010年的时候,是加州大学伯克利分校的研究团队弄出来的,目的就是想搞个新的、开放的指令集架构,能跟上现代计算的需要。到了2015年,专门成立了个RISC-V基金会,让这个架构更标准,也更好地推广开了。这几年啊,这个RISC-V的生态系统发展得可快了,好多公司和机构都加入了RISC-V International,还推出了不少RISC-V
      丙丁先生 2025-01-21 12:10 112浏览
    • 本文介绍瑞芯微开发板/主板Android配置APK默认开启性能模式方法,开启性能模式后,APK的CPU使用优先级会有所提高。触觉智能RK3562开发板演示,搭载4核A53处理器,主频高达2.0GHz;内置独立1Tops算力NPU,可应用于物联网网关、平板电脑、智能家居、教育电子、工业显示与控制等行业。源码修改修改源码根目录下文件device/rockchip/rk3562/package_performance.xml并添加以下内容,注意"+"号为添加内容,"com.tencent.mm"为AP
      Industio_触觉智能 2025-01-17 14:09 164浏览
    • 日前,商务部等部门办公厅印发《手机、平板、智能手表(手环)购新补贴实施方案》明确,个人消费者购买手机、平板、智能手表(手环)3类数码产品(单件销售价格不超过6000元),可享受购新补贴。每人每类可补贴1件,每件补贴比例为减去生产、流通环节及移动运营商所有优惠后最终销售价格的15%,每件最高不超过500元。目前,京东已经做好了承接手机、平板等数码产品国补优惠的落地准备工作,未来随着各省市关于手机、平板等品类的国补开启,京东将第一时间率先上线,满足消费者的换新升级需求。为保障国补的真实有效发放,基于
      华尔街科技眼 2025-01-17 10:44 221浏览
    • Ubuntu20.04默认情况下为root账号自动登录,本文介绍如何取消root账号自动登录,改为通过输入账号密码登录,使用触觉智能EVB3568鸿蒙开发板演示,搭载瑞芯微RK3568,四核A55处理器,主频2.0Ghz,1T算力NPU;支持OpenHarmony5.0及Linux、Android等操作系统,接口丰富,开发评估快人一步!添加新账号1、使用adduser命令来添加新用户,用户名以industio为例,系统会提示设置密码以及其他信息,您可以根据需要填写或跳过,命令如下:root@id
      Industio_触觉智能 2025-01-17 14:14 122浏览
    •  万万没想到!科幻电影中的人形机器人,正在一步步走进我们人类的日常生活中来了。1月17日,乐聚将第100台全尺寸人形机器人交付北汽越野车,再次吹响了人形机器人疯狂进厂打工的号角。无独有尔,银河通用机器人作为一家成立不到两年时间的创业公司,在短短一年多时间内推出革命性的第一代产品Galbot G1,这是一款轮式、双臂、身体可折叠的人形机器人,得到了美团战投、经纬创投、IDG资本等众多投资方的认可。作为一家成立仅仅只有两年多时间的企业,智元机器人也把机器人从梦想带进了现实。2024年8月1
      刘旷 2025-01-21 11:15 399浏览
    •     IPC-2581是基于ODB++标准、结合PCB行业特点而指定的PCB加工文件规范。    IPC-2581旨在替代CAM350格式,成为PCB加工行业的新的工业规范。    有一些免费软件,可以查看(不可修改)IPC-2581数据文件。这些软件典型用途是工艺校核。    1. Vu2581        出品:Downstream     
      电子知识打边炉 2025-01-22 11:12 55浏览
    • 现在为止,我们已经完成了Purple Pi OH主板的串口调试和部分配件的连接,接下来,让我们趁热打铁,完成剩余配件的连接!注:配件连接前请断开主板所有供电,避免敏感电路损坏!1.1 耳机接口主板有一路OTMP 标准四节耳机座J6,具备进行音频输出及录音功能,接入耳机后声音将优先从耳机输出,如下图所示:1.21.2 相机接口MIPI CSI 接口如上图所示,支持OV5648 和OV8858 摄像头模组。接入摄像头模组后,使用系统相机软件打开相机拍照和录像,如下图所示:1.3 以太网接口主板有一路
      Industio_触觉智能 2025-01-20 11:04 150浏览
    •  光伏及击穿,都可视之为 复合的逆过程,但是,复合、光伏与击穿,不单是进程的方向相反,偏置状态也不一样,复合的工况,是正偏,光伏是零偏,击穿与漂移则是反偏,光伏的能源是外来的,而击穿消耗的是结区自身和电源的能量,漂移的载流子是 客席载流子,须借外延层才能引入,客席载流子 不受反偏PN结的空乏区阻碍,能漂不能漂,只取决于反偏PN结是否处于外延层的「射程」范围,而穿通的成因,则是因耗尽层的过度扩张,致使跟 端子、外延层或其他空乏区 碰触,当耗尽层融通,耐压 (反向阻断能力) 即告彻底丧失,
      MrCU204 2025-01-17 11:30 182浏览
    • 2024年是很平淡的一年,能保住饭碗就是万幸了,公司业绩不好,跳槽又不敢跳,还有一个原因就是老板对我们这些员工还是很好的,碍于人情也不能在公司困难时去雪上加霜。在工作其间遇到的大问题没有,小问题还是有不少,这里就举一两个来说一下。第一个就是,先看下下面的这个封装,你能猜出它的引脚间距是多少吗?这种排线座比较常规的是0.6mm间距(即排线是0.3mm间距)的,而这个规格也是我们用得最多的,所以我们按惯性思维来看的话,就会认为这个座子就是0.6mm间距的,这样往往就不会去细看规格书了,所以这次的运气
      wuliangu 2025-01-21 00:15 186浏览
    • 临近春节,各方社交及应酬也变得多起来了,甚至一月份就排满了各式约见。有的是关系好的专业朋友的周末“恳谈会”,基本是关于2025年经济预判的话题,以及如何稳定工作等话题;但更多的预约是来自几个客户老板及副总裁们的见面,他们为今年的经济预判与企业发展焦虑而来。在聊天过程中,我发现今年的聊天有个很有意思的“点”,挺多人尤其关心我到底是怎么成长成现在的多领域风格的,还能掌握一些经济趋势的分析能力,到底学过哪些专业、在企业管过哪些具体事情?单单就这个一个月内,我就重复了数次“为什么”,再辅以我上次写的:《
      牛言喵语 2025-01-22 17:10 41浏览
    • 高速先生成员--黄刚这不马上就要过年了嘛,高速先生就不打算给大家上难度了,整一篇简单但很实用的文章给大伙瞧瞧好了。相信这个标题一出来,尤其对于PCB设计工程师来说,心就立马凉了半截。他们辛辛苦苦进行PCB的过孔设计,高速先生居然说设计多大的过孔他们不关心!另外估计这时候就跳出很多“挑刺”的粉丝了哈,因为翻看很多以往的文章,高速先生都表达了过孔孔径对高速性能的影响是很大的哦!咋滴,今天居然说孔径不关心了?别,别急哈,听高速先生在这篇文章中娓娓道来。首先还是要对各位设计工程师的设计表示肯定,毕竟像我
      一博科技 2025-01-21 16:17 101浏览
    • 数字隔离芯片是一种实现电气隔离功能的集成电路,在工业自动化、汽车电子、光伏储能与电力通信等领域的电气系统中发挥着至关重要的作用。其不仅可令高、低压系统之间相互独立,提高低压系统的抗干扰能力,同时还可确保高、低压系统之间的安全交互,使系统稳定工作,并避免操作者遭受来自高压系统的电击伤害。典型数字隔离芯片的简化原理图值得一提的是,数字隔离芯片历经多年发展,其应用范围已十分广泛,凡涉及到在高、低压系统之间进行信号传输的场景中基本都需要应用到此种芯片。那么,电气工程师在进行电路设计时到底该如何评估选择一
      华普微HOPERF 2025-01-20 16:50 73浏览
    我要评论
    0
    点击右上角,分享到朋友圈 我知道啦
    请使用浏览器分享功能 我知道啦