当前位置: 首页 > wzjs >正文

百度网站好评百度广告收费

百度网站好评,百度广告收费,网站开发需要学习,域名备案网站备案二进制信号量&#xff1a;线程同步的基础 什么是二进制信号量&#xff1f; 二进制信号量是一种特殊的信号量&#xff0c;其值只能是0或1。它是最简单的线程同步机制之一&#xff0c;常用于线程间的简单协调。 #include <semaphore.h>sem_t sem; // 声明二进制信号量 se…

二进制信号量:线程同步的基础

什么是二进制信号量?

二进制信号量是一种特殊的信号量,其值只能是0或1。它是最简单的线程同步机制之一,常用于线程间的简单协调。

#include <semaphore.h>sem_t sem; // 声明二进制信号量
sem_init(&sem, 0, 1); // 初始化,第二个参数0表示线程间共享,初始值为1

二进制信号量的工作原理:

  • 值为1:资源可用,线程可以继续执行

  • 值为0:资源不可用,线程必须等待

二进制信号量的基本操作

  1. sem_wait() - 获取信号量

    sem_wait(&sem); // 如果sem>0则减1,否则阻塞
  2. sem_post() - 释放信号量

    sem_post(&sem); // 信号量值加1
  3. sem_getvalue() - 获取当前信号量值

    int val;
    sem_getvalue(&sem, &val);

二进制信号量与互斥锁的区别

虽然二进制信号量和互斥锁看起来很相似,但它们有重要区别:

特性二进制信号量互斥锁
所有者无所有者概念必须由加锁线程解锁
初始值可设为0或1通常初始为1
用途线程同步、事件通知保护临界区
性能稍慢更快

实际应用中的选择

  • 使用信号量的场景

    • 需要线程间通知(如生产者-消费者)

    • 需要限制并发访问数量

  • 使用互斥锁的场景

    • 保护共享资源的访问

    • 需要确保解锁由同一线程完成

获取信号量的值

获取信号量的当前值可以使用sem_getvalue()

在并发编程中,条件变量(cond)信号量(semaphore)互斥锁(mutex)是三种核心的线程同步机制,它们有各自的特点和适用场景。以下是它们的详细对比和解释:


1. 互斥锁(Mutex)

作用
  • 保护共享资源:确保同一时间只有一个线程能访问临界区(critical section),防止数据竞争。

特点
  • 二元状态:只有锁定(locked)和解锁(unlocked)两种状态。

  • 所有权:必须由加锁的线程解锁(不能跨线程解锁)。

  • 阻塞行为:其他线程尝试获取已锁定的互斥锁时会被阻塞。

C语言示例

 

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;void* thread_func() {pthread_mutex_lock(&mutex);  // 加锁// 临界区代码pthread_mutex_unlock(&mutex); // 解锁
}

适用场景
  • 保护共享变量(如全局计数器)。

  • 需要确保操作的原子性时。


2. 信号量(Semaphore)

作用
  • 控制并发访问数量:允许多个线程(数量可配置)同时访问资源。

  • 线程同步:协调线程的执行顺序(如生产者-消费者模型)。

特点
  • 计数器:信号量是一个非负整数,表示可用资源数。

  • 无所有者:任何线程都可以释放(post)信号量。

  • 阻塞行为:当信号量为0时,wait操作会阻塞线程。

C语言示例

 

#include <semaphore.h>
sem_t sem;void init() {sem_init(&sem, 0, 3);  // 初始值为3,允许3个线程并发
}void* thread_func() {sem_wait(&sem);  // 信号量减1(若为0则阻塞)// 访问共享资源sem_post(&sem);  // 信号量加1
}

适用场景
  • 限制数据库连接池的并发数。

  • 实现生产者-消费者队列。


3. 条件变量(Condition Variable, cond)

作用
  • 线程间通知:允许线程在某个条件满足时被唤醒,避免忙等待(busy-waiting)。

  • 配合互斥锁使用:通常与互斥锁一起实现复杂的同步逻辑。

特点
  • 无状态:本身不存储条件,需依赖外部条件判断。

  • 等待/通知机制:线程通过wait主动阻塞,通过signalbroadcast唤醒。

C语言示例

 

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
int ready = 0;  // 条件标志// 等待线程
void* consumer() {pthread_mutex_lock(&mutex);while (!ready) {pthread_cond_wait(&cond, &mutex);  // 释放锁并阻塞}// 条件满足后的操作pthread_mutex_unlock(&mutex);
}// 通知线程
void* producer() {pthread_mutex_lock(&mutex);ready = 1;pthread_cond_signal(&cond);  // 唤醒一个等待线程pthread_mutex_unlock(&mutex);
}

适用场景
  • 实现线程间的事件通知(如任务队列非空时唤醒工作线程)。

  • 避免轮询检查条件(节省CPU资源)。


三者的核心区别

特性互斥锁(Mutex)信号量(Semaphore)条件变量(cond)
用途保护临界区控制并发访问数量线程间事件通知
是否持有资源是(锁的持有者)否(仅计数器)否(需外部条件判断)
释放操作必须由加锁线程解锁任意线程可post任意线程可signal
阻塞行为获取锁失败时阻塞信号量为0时阻塞显式调用wait时阻塞
典型场景共享变量修改连接池限流生产者-消费者模型

如何选择?

  1. 需要保护共享数据互斥锁
    (如:多个线程修改同一个全局变量)

  2. 需要限制并发数信号量
    (如:最多5个线程同时访问数据库)

  3. 需要等待某个条件成立条件变量 + 互斥锁
    (如:任务队列非空时唤醒线程)


常见问题解答

Q1: 为什么条件变量需要配合互斥锁?
  • 条件变量的wait操作会临时释放锁并阻塞,被唤醒后重新获取锁,确保条件检查的原子性。

Q2: 二进制信号量(初始值为1)和互斥锁的区别?
  • 二进制信号量可以被任意线程释放,而互斥锁必须由加锁线程解锁。

Q3: 信号量的post和条件变量的signal有何不同?
  • sem_post会增加信号量计数器,可能唤醒多个线程(取决于wait的线程数)。

  • pthread_cond_signal仅唤醒一个等待线程(不涉及计数器)。


深入理解并行与并发及C语言线程池实现

并行(Parallelism) vs 并发(Concurrency)

并行是指多个任务真正同时执行,需要多核CPU硬件支持。在C语言中,我们可以通过创建多个线程并分配到不同CPU核心上来实现并行计算。

 

// 并行计算数组元素平方的示例
void* parallel_square(void* arg) {int* data = (int*)arg;for (int i = 0; i < CHUNK_SIZE; i++) {data[i] = data[i] * data[i]; // 无共享数据,可真正并行}return NULL;
}// 创建线程并行处理
pthread_t threads[4];
int chunks[4][CHUNK_SIZE];
for (int i = 0; i < 4; i++) {pthread_create(&threads[i], NULL, parallel_square, chunks[i]);
}

并发是指多个任务交替执行,在单核CPU上通过时间片轮转实现"看似同时"的效果。典型的并发模式是使用互斥锁保护共享资源:

 

pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
int shared_counter = 0;void* concurrent_increment(void* arg) {pthread_mutex_lock(&lock);shared_counter++; // 临界区pthread_mutex_unlock(&lock);return NULL;
}

关键区别:

  • 并行需要多核硬件,并发可在单核实现

  • 并行是物理上的同时执行,并发是逻辑上的交替执行

  • 并行性能可线性扩展,并发性能受限于上下文切换开销

这段代码实现了一个多线程任务队列系统,结合了互斥锁(pthread_mutex_t)和条件变量(pthread_cond_t)来安全地分配和处理任务。以下是详细解析:


1. 核心组件

(1)数据结构

 

typedef struct Task {int a, b;  // 任务参数
} Task;Task taskQueue[256];  // 任务队列
int taskCount = 0;    // 当前任务数

  • 任务队列:固定大小的数组(256),存储待处理的 Task 结构体。

  • 任务计数:记录队列中当前的任务数量。

(2)同步机制

 

pthread_mutex_t mutexQueue;  // 保护任务队列的互斥锁
pthread_cond_t condQueue;    // 通知线程有新任务的条件变量

  • 互斥锁:确保对 taskQueuetaskCount 的访问是线程安全的。

  • 条件变量:当队列为空时,让线程等待;当有新任务时,唤醒线程。


2. 关键函数

(1)提交任务 (submitTask)

 

void submitTask(Task task) {pthread_mutex_lock(&mutexQueue);taskQueue[taskCount] = task;  // 添加任务到队列尾部taskCount++;pthread_mutex_unlock(&mutexQueue);pthread_cond_signal(&condQueue);  // 唤醒一个等待的线程
}

  • 线程安全:通过互斥锁保护队列操作。

  • 信号通知:调用 pthread_cond_signal 唤醒一个阻塞的线程(如果有)。

(2)线程执行逻辑 (startThread)

 

void* startThread(void* args) {while (1) {Task task;// 获取任务(加锁)pthread_mutex_lock(&mutexQueue);while (taskCount == 0) {pthread_cond_wait(&condQueue, &mutexQueue);  // 队列空则等待}// 从队列头部取出任务task = taskQueue[0];for (int i = 0; i < taskCount - 1; i++) {taskQueue[i] = taskQueue[i + 1];  // 队列前移}taskCount--;pthread_mutex_unlock(&mutexQueue);// 执行任务(无锁,可并行)executeTask(&task);}
}

  • 队列空时等待pthread_cond_wait 会释放锁并阻塞,直到被 pthread_cond_signal 唤醒。

  • 任务调度:采用 FIFO(先进先出) 策略处理任务。

  • 并行执行executeTask 在锁外执行,多个线程可同时处理不同任务。

(3)任务执行 (executeTask)

 

void executeTask(Task* task) {int result = task->a + task->b;printf("The sum of %d and %d is %d\n", task->a, task->b, result);
}

  • 无锁操作:纯计算任务,可完全并行。


3. 主程序流程

  1. 初始化

    • 创建 4 个线程(THREAD_NUM=4)。

    • 初始化互斥锁和条件变量。

  2. 生成任务

     
    for (i = 0; i < 100; i++) {Task t = { .a = rand() % 100, .b = rand() % 100 };submitTask(t);  // 提交100个随机任务
    }
  3. 线程结束

    • 主线程等待所有子线程完成(实际因 while(1) 永不结束,需改进)。


4. 并发与并行分析

特性实现方式
并发控制互斥锁保护任务队列,条件变量优化线程等待/唤醒。
并行计算多个线程同时执行 executeTask(无锁部分)。
任务调度

线程竞争获取任务,队列为空时阻塞,避免忙等待。

C语言的线程池API设计与实现

线程池是一种管理多个线程的技术,可以避免频繁创建销毁线程的开销。

基本结构

 

typedef struct {pthread_t* threads;TaskQueue* queue;pthread_mutex_t lock;pthread_cond_t notify;int thread_count;int shutdown;
} ThreadPool;

核心API

  1. 创建线程池

 

ThreadPool* tp_create(int thread_count) {ThreadPool* pool = malloc(sizeof(ThreadPool));// 初始化互斥锁、条件变量等return pool;
}

  1. 添加任务

 

void tp_add_task(ThreadPool* pool, void (*func)(void*), void* arg) {Task task = {func, arg};pthread_mutex_lock(&pool->lock);enqueue(pool->queue, task);pthread_cond_signal(&pool->notify);pthread_mutex_unlock(&pool->lock);
}

  1. 工作线程函数

 

void* worker_thread(void* arg) {ThreadPool* pool = (ThreadPool*)arg;while(1) {pthread_mutex_lock(&pool->lock);while(pool->queue->size == 0 && !pool->shutdown) {pthread_cond_wait(&pool->notify, &pool->lock);}// 获取并执行任务pthread_mutex_unlock(&pool->lock);}return NULL;
}

线程池中的C函数指针

在线程池实现中,函数指针用于表示任务:

 

typedef struct {void (*function)(void*);void* argument;
} Task;

使用方法

  1. 定义任务函数

 

void print_hello(void* arg) {int id = *(int*)arg;printf("Hello from task %d\n", id);
}

  1. 提交任务

 

int task_id = 42;
tp_add_task(pool, print_hello, &task_id);

高级技巧

使用函数指针数组实现多态任务处理:

 

void (*handlers[])(void*) = {handle_type_a, handle_type_b, handle_type_c};// 根据任务类型调用不同处理函数
void process_task(Task* task) {int type = get_task_type(task);handlers[type](task->argument);
}

遇到的问题与解决方案

问题1:为什么我的线程池没有输出?

现象:提交任务后程序无输出,直接退出。

原因:主线程在提交任务后立即退出,导致整个进程终止。

解决方案

 

// 添加等待机制
while(tasks_not_completed) {sleep(1);
}

问题2:如何避免线程池中的任务饥饿?

解决方案

  1. 实现任务优先级队列

  2. 使用工作窃取(Work Stealing)算法

  3. 限制每个线程处理的任务数量

问题3:信号量和互斥锁混用时死锁

错误代码

 

void foo() {pthread_mutex_lock(&mutex);sem_wait(&sem);  // 可能死锁// ...
}

正确做法:保持锁的获取顺序一致,或重构代码减少锁的嵌套。

 


文章转载自:

http://LSEZ8adA.zrwLz.cn
http://gtnsZpcU.zrwLz.cn
http://BfRfZ52e.zrwLz.cn
http://XDGs3jQg.zrwLz.cn
http://HWf5oQ7k.zrwLz.cn
http://AokKhmXb.zrwLz.cn
http://5V1aPsLG.zrwLz.cn
http://LWTQ4lEf.zrwLz.cn
http://jrvUmHZR.zrwLz.cn
http://5SdhOSVT.zrwLz.cn
http://0hL5weuD.zrwLz.cn
http://OA7SxHFQ.zrwLz.cn
http://8PKNa43b.zrwLz.cn
http://mE7BVNBt.zrwLz.cn
http://wncR2g5U.zrwLz.cn
http://pzonQOyu.zrwLz.cn
http://DzZ0ceVF.zrwLz.cn
http://HIolztdh.zrwLz.cn
http://fqTre58L.zrwLz.cn
http://PLYM4YPT.zrwLz.cn
http://nVTwUdFL.zrwLz.cn
http://ZeMlBxoG.zrwLz.cn
http://QvA9pfPv.zrwLz.cn
http://oNV6rrr0.zrwLz.cn
http://tg9dzNJ3.zrwLz.cn
http://5y9q2x3i.zrwLz.cn
http://4Frv8lqa.zrwLz.cn
http://Y3YTclE5.zrwLz.cn
http://x14pgDdU.zrwLz.cn
http://E1ERgTLT.zrwLz.cn
http://www.dtcms.com/wzjs/738072.html

相关文章:

  • 印刷网站开发的可行性报告263企业邮箱免费登录入口
  • 网站定制解决方案沈阳商城网站制作
  • 网页设计与制作教程期末考试试题宿迁网站优化
  • 网站死链接是什么广州平面设计招聘
  • 天津专门做网站的公司的电话实体店100个营销策略
  • wordpress做网站过程wordpress播放器源码
  • 教育门户网站建站做响应式网站代码
  • 信息化建设办公室网站石家庄ui设计公司
  • 有哪个网站是成都中科大旗做的WordPress360收录查询
  • 云南省住房和城乡建设局网站企业网站建设论文5000
  • 怎么欣赏一个网站设计图2023年小学生简短小新闻
  • 工信部 诚信网站备案wordpress不显示全文
  • 中山网站建设怎么样坪山区坪山街道六联社区
  • html网站 怎么做seo公众出行服务网站建设
  • 海口市住房和城乡建设局网站高端的赣州网站建设
  • 多仓库版仓库管理网站建设源码网站被域名重定向
  • 帝国网站整站迁移杭州产品设计公司有哪些
  • 河北建设厅网站初始密码二级建造师报名官网
  • 做的网站有广告整合营销的成功案例
  • python适合网站开发吗wordpress电影插件
  • 烟台市做网站网站开发专业的建设设想
  • 启动培训网站建设的请示网站建设的主要情况说明书
  • 用外服务器做网站建h5网站费用
  • 宿州网站建设电话g3云推广是什么
  • 重庆美食制作重庆seo排名技术
  • 乐山建设企业网站宣威市住房与城乡建设局网站
  • 好的h5制作网站模板wordpress防攻击代码
  • 网站开发使用哪种工具好黑河做网站的
  • 济南智能网站建设咨询电话建设网站过程中
  • 游戏点卡平台网站开发宁夏建设银行官方网站