首页 > 其他分享 >libuv线程

libuv线程

时间:2024-05-13 16:53:31浏览次数:16  
标签:rwlock int void uv 线程 async libuv

1、概述

  libuv的线程API与Linux的pthread的API在使用方法和语义上很接近,因为要跨平台,所以libuv支持的线程API个数很有限。libuv中只有一个主线程,主线程上只有一个event loop。如下为创建线程的一个简单示例:

#include <stdio.h>
#include <uv.h>

void thread_fun(void* arg) { //线程方法
    fprintf(stdout, "thread start\n");
    int param = *((int*)arg);
}

int main() {
    int param = 100;
    uv_thread_t thread_id;
    uv_thread_create(&thread_id, thread_fun, &param); //创建线程并开始

    uv_thread_join(&thread_id); //等待线程结束
    return 0;
}

2、线程同步

  ①、互斥量

UV_EXTERN int uv_mutex_init(uv_mutex_t* handle); //执行成功返回0,错误返回错误码
UV_EXTERN void uv_mutex_lock(uv_mutex_t* handle); //调试模式下出错会引发abort()中断,而不是返回错误码
UV_EXTERN int uv_mutex_trylock(uv_mutex_t* handle); //libuv的API中并未实现递归上锁
UV_EXTERN void uv_mutex_unlock(uv_mutex_t* handle);
UV_EXTERN void uv_mutex_destroy(uv_mutex_t* handle);

  ②、读写锁

int    uv_rwlock_init(uv_rwlock_t* rwlock);
void uv_rwlock_rdlock(uv_rwlock_t* rwlock); //读
int    uv_rwlock_tryrdlock(uv_rwlock_t* rwlock);
void uv_rwlock_rdunlock(uv_rwlock_t* rwlock);
void uv_rwlock_wrlock(uv_rwlock_t* rwlock); //写
int    uv_rwlock_trywrlock(uv_rwlock_t* rwlock);
void uv_rwlock_wrunlock(uv_rwlock_t* rwlock);
void uv_rwlock_destroy(uv_rwlock_t* rwlock);

  ③、屏障

  libuv中屏障相关方法分别对应linux中pthread_xxx()相关方法的功能,“屏障”就相当于是线程的栏杆。可以将多个线程挡在同一栏杆前,直到所有线程到齐,然后撤下栏杆同时放行。

int uv_barrier_init(uv_barrier_t* barrier, unsigned int count); //初始化屏障并指定要等待的线程个数
int uv_barrier_wait(uv_barrier_t* barrier); //在线程中调用该方法,告诉屏障我已经到达栏杆处了,然后屏障会检查是否所有线程都已经到达,否的话已经到达栏杆的线程会阻塞,是的话放行所有线程
void uv_barrier_destroy(uv_barrier_t* barrier); //释放屏障

  ④、其它

  libuv同样支持信号量,条件变量,而且API的使用方法和pthread中的用法很类似,具体可以参考libuv文档

  libuv中还提供一个uv_once()方法,在多个线程中通过uv_once来调用指定方法的话,该方法只会被一个线程所调用,如下所示两个线程执行完毕后g_i的值是1:

uv_once_t once_only = UV_ONCE_INIT;
int g_i = 0;

void increment() {
    i++;
}

void thread1() {
    /* ... work */
    uv_once(&once_only, increment);
}

void thread2() {
    /* ... work */
    uv_once(&once_only, increment);
}

 3、TLS(线程局部存储)

  TLS就是只能被线程内的各个方法访问的变量,该变量不能被其它线程访问。如下为libuv中TLS相关方法,具体可以参考libuv文档

int uv_key_create(uv_key_t* key) //对应pthread中的pthread_key_create()
void uv_key_delete(uv_key_t* key)
void* uv_key_get(uv_key_t* key)
void uv_key_set(uv_key_t* key, void* value)

 4、任务队列

  uv_queue_work()会使用线程池执行指定的任务(线程池默认大小为4,可以通过环境变量UV_THREADPOOL_SIZE来设置),而且当任务完成后会在主线程中运行指定的回调。uv_queue_work()的第二个参数需要一个uv_work_t(任务方法和完成通知回调方法的参数),可以通过uv_work_t::data域来传递上下文数据,如下所示将uv_work_t放到上下文数据结构中的话,可以一次malloc把uv_work_t和数据都申请了出来。

  uv_cancel()可以取消工作队列中的任务,其参数为uv_work_t。只有还未开始的任务可以被取消,此时回调通知方法中的status参数值为UV_ECANCELED,如果任务已经开始执行或者执行完毕,uv_cancel()返回0。uv_cancel()同样可以用在uv_fs_t和uv_getaddrinfo_t请求上。

#include <stdio.h>
#include <uv.h>

struct SData {
    uv_work_t req;
    char* str;
    int n = 0;
};

void fun(uv_work_t* req) {
    SData* pBaton = (SData*)req->data;

}

void after_fun(uv_work_t* req, int status) {
    if(status == UV_ECANCELED) { //任务被取消

    }
    else {

    }

    SData* pBaton = (SData*)req->data;
    free(pBaton->str);
    free(pBaton);
}

int main() {  
    uv_loop_t* loop = uv_default_loop();

    SData* pBaton = (SData*)malloc(sizeof(SData));
    pBaton->req.data = (void*)pBaton;
    pBaton->str = _strdup("str");
    uv_queue_work(loop, &pBaton->req, fun, after_fun);
   
    return uv_run(loop, UV_RUN_DEFAULT);
}

5、异步调用 

  使用uv_async_init()和uv_async_send()可以异步的执行一个方法,该方法会在event-loop主线程中执行。uv_async_send()相当于是向主线程发了一个消息,主线程收到消息后会执行uv_async_init()设置的方法。有可能多次调用uv_async_send后只运行了一次回调函数:比如你调用了两次uv_async_send(), 而 libuv很忙,暂时还没有机会运行回调函数。

#include <stdio.h>
#include <uv.h>

uv_async_t async; //异步对象
uv_work_t req;

void thread_fun(uv_work_t* req) {

    async.data = (void*)_strdup("data");
    uv_async_send(&async); //执行异步对象
}

void after_thread_fun(uv_work_t* req, int status) {
   
    uv_close((uv_handle_t*)&async, NULL); //释放异步对象,任务完成的回调after_thread_fun()会在异步方法async_fun()之后执行
}

void async_fun(uv_async_t* handle) {
    char* pData = (char*)handle->data;

    free(pData);
}

int main() {  
    uv_loop_t* loop = uv_default_loop();

    uv_async_init(loop, &async, async_fun); //初始化异步对象

    uv_queue_work(loop, &req, thread_fun, after_thread_fun);
   
    return uv_run(loop, UV_RUN_DEFAULT);
}

 

标签:rwlock,int,void,uv,线程,async,libuv
From: https://www.cnblogs.com/milanleon/p/18186827

相关文章

  • C#异步与多线程
    c#的异步与多线程异步与多线程首先,异步是相对于同步的一个概念,在同步环境下,程序允许至某处需要等待的位置,会发生阻塞,直到达到条件才会继续向下运行;而异步操作则可以在需要等待的位置,跳过等待,执行其他内容,通常异步处理的事务不能相互存在影响。多线程指的是,同时使用多个线程执行......
  • WinForm中UI控件不支持从非创建控件的线程进行访问
    背景在WindowsForms应用程序中,UI控件(如按钮、文本框等)被设计为不支持从非创建控件的线程(通常是主UI线程)进行访问。尝试从其他线程访问UI控件会导致不可预测的行为,包括应用程序崩溃。Control.CheckForIllegalCrossThreadCalls属性用于在调试过程中帮助开发者发现这类潜在问......
  • mybatis多线程插入数据表已经事务回滚
    importlombok.extern.slf4j.Slf4j;importorg.apache.commons.collections4.CollectionUtils;importorg.apache.commons.collections4.ListUtils;importorg.apache.ibatis.session.ExecutorType;importorg.apache.ibatis.session.SqlSession;importorg.apache.ibati......
  • C#多线程
    目录C#线程概述定义程序、进程、线程基本语法C#可以通过Thread、ThreadPool、Task(推荐)创建线程。前台线程和后台线程共享数据保护机制优缺点/应用场景优缺点常见的应用场景总结C#线程概述定义线程(thread)是计算机科学中将进程划分为两个或多个线程(实例)或子进程,由单处理器(单线程......
  • 线程池中抛出的异常,主线程可以catch到吗
    印象中,线程池抛出的异常主线程可以catch到,但前段时间碰到个问题,在系统出现异常时,由于线程池任务中没有catch异常的代码,主线程虽有catch异常代码,但却没有catch到异常,导致排查问题比较费劲。故对此处进行研究,并记录。一、JVM异常处理先来看一下jvm对未捕获的异常如何处理1......
  • Java面试题:线程池内“闹情绪”的线程,怎么办?
    在Java中,线程池中工作线程出现异常的时候,默认会把异常往外抛,同时这个工作线程会因为异常而销毁,我们需要自己去处理对应的异常,异常处理的方法有几种:在传递的任务中去处理异常,对于每个提交到线程池中的执行的任务,可以提前通过异常进行捕获,这样即便出现了异常,也不会影响线程池中的......
  • 多线程应用
    importtimeimportthreadingdeffunc_one(name):fornuminrange(1,6):print(f"{name}第{num}次执行")time.sleep(1)deffunc_two(name):fornuminrange(1,6):print(f"{name}第{num}次执行")time.sleep(1......
  • Java-线程-并发解决方案
    0.背景在[Java-线程-并发]这篇文章中,我们引入了并发场景下的一些问题,并在末尾给出了几种常见的解决方案。1.方案1.1synchronizedsynchronized是Java中的一个关键字,用于提供同步机制,保证多线程环境下对共享资源的安全访问。通过使用synchronized,Java虚拟机(JVM)保证同一时......
  • 爬虫多线程代码调试
    第一次调试fromthreadingimportThreadfromfake_useragentimportUserAgentimportrequestsfromtimeimportsleepforiinrange(1,11):url=f"https://www.hupu.com/home/v1/news?pageNo={i}&pageSize=50"headers={"User-......
  • Java-线程-并发问题和ConcurrentHashMap
    0.背景在经典八股文中,我们会背:啊,hashmap是线程不安全的,concurrentHashMap是线程安全的。然后呢,又背:啊,为啥ConcurrentHashMap是安全的,因为加锁了。好好好,接着八股:啊,啥啥分段锁。本文,结合实际例子来进行分析,这他妈的到底是在叭叭啥。一切,从一个Hashmap的demo谈起。pu......