最新文�? 【c_c++项目】手把手带你实现一个内存型数据库(kv存储) 【C++】模仿tcmalloc从零实现一个高并发内存池(一) 【C++】模仿tcmalloc从零实现一个高并发内存池(二) 【C++】模仿tcmalloc从零实现一个高并发内存池(三) 【C++】模仿tcmalloc从零实现一个高并发内存池(四)
解锁linux多线程编程,从入门到精通 历史版本:
上次修改时间:
\", tg->list[path[i]].s.id);\n\n }\n\n printf(\"%ld\\n\", tg->list[path[i]].s.id);\n\n}\n\n//深度优先搜索-idx:结点序号(要遍历的第一个结点)\nint DFS(int idx) {\n\n struct vertex *ver = &tg->list[idx];\n if (visited[idx] == 1) { //只有该结点是遍历过,那么就是存在环(死锁)\n path[k++] = idx;\n print_deadlock();\n deadlock = 1;\n return 0;\n }\n visited[idx] = 1;//遍历过后就将该结点标志设置为1\n path[k++] = idx;\n while (ver->next != NULL) {\n DFS(search_vertex(ver->next->s));//深度遍历下一个结点\n k --;//idx的某一条边的所有已经遍历完成,路径有回退的操作.这里有点不太好理解,可以自己画一个很简单的有向图进行分析,\n ver = ver->next;//指向该节点的下一条边\n }\n return 1;\n\n}\n\n//从idx结点开始遍历,看是否存在环\nint search_for_cycle(int idx) {\n\n struct vertex *ver = &tg->list[idx];\n visited[idx] = 1;\n k = 0;\n path[k++] = idx;//记下idx序号结点的路径编码\n\n while (ver->next != NULL) {\n int i = 0;\n for (i = 0;i < tg->num;i ++) {//除该节点之外的所有结点将其标志设置设置为0\n if (i == idx) continue\n visited[i] = 0;\n }\n\n for (i = 1;i <= MAX;i ++) {\n path[i] = -1;//路径编码设置为-1,代表除起始节点的所有结点还不存在路径即:path[max]={idx,-1.-1.-1.-1......}\n }\n k = 1;\n DFS(search_vertex(ver->next->s));//从该节点的某个边的节点开始遍历\n ver = ver->next;\n }\n\n}\n\n#if 0\nint main() {\n\n tg = (struct task_graph*)malloc(sizeof(struct task_graph));\n tg->num = 0;\n\n struct source_type v1;\n v1.id = 1;\n v1.type = PROCESS;\n add_vertex(v1);\n\n struct source_type v2;\n v2.id = 2;\n v2.type = PROCESS;\n add_vertex(v2);\n\n struct source_type v3;\n v3.id = 3;\n v3.type = PROCESS;\n add_vertex(v3);\n\n struct source_type v4;\n v4.id = 4;\n v4.type = PROCESS;\n add_vertex(v4);\n\n \n struct source_type v5;\n v5.id = 5;\n v5.type = PROCESS;\n add_vertex(v5);\n\n\n add_edge(v1, v2);\n add_edge(v2, v3);\n add_edge(v3, v4);\n add_edge(v4, v5);\n add_edge(v3, v1);\n \n search_for_cycle(search_vertex(v1));\n\n}\n#endif\n\n\n#endif\n\n//检测是否有死锁\nvoid check_dead_lock(void) {\n\n int i = 0;\n\n deadlock = 0;\n for (i = 0;i < tg->num;i ++) {//对所有结点进行遍历-看结点是否存在环\n if (deadlock == 1) break;\n search_for_cycle(i);\n }\n\n if (deadlock == 0) {\n printf(\"no deadlock\\n\");\n }\n\n}\n\n//检测是否有死锁的线程\nstatic void *thread_routine(void *args) {\n\n while (1) {\n sleep(5);\n check_dead_lock();\n\n }\n\n}\n\nvoid start_check(void) {\n\n tg = (struct task_graph*)malloc(sizeof(struct task_graph));\n tg->num = 0;\n tg->lockidx = 0;\n pthread_t tid;\n pthread_create(&tid, NULL, thread_routine, NULL);\n\n}\n\n#if 1\n//lock:mutex id \n//判断mutex id是否在所有的锁列表中\nint search_lock(uint64 lock) {\n\n int i = 0;\n \n for (i = 0;i < tg->lockidx;i ++) {\n \n if (tg->locklist[i].lock_id == lock) {\n return i;\n }\n }\n\n return -1;\n}\n\n//lock:mutex id\n//\nint search_empty_lock(uint64 lock) {\n\n int i = 0;\n \n for (i = 0;i < tg->lockidx;i ++) {\n \n if (tg->locklist[i].lock_id == 0) {\n return i;\n }\n }\n return tg->lockidx;\n}\n\n#endif\n\n//原子操作-++操作(这里涉及到底层码-没必要细细研究)\nint inc(int *value, int add) {\n\n int old; \n __asm__ volatile(\n \"lock;xaddl %2, %1;\"\n : \"=a\"(old)\n : \"m\"(*value), \"a\" (add)\n : \"cc\", \"memory\"\n );\n \n return old;\n}\n\nvoid print_locklist(void) {\n int i = 0;\n printf(\"print_locklist: \\n\");\n printf(\"---------------------\\n\");\n for (i = 0;i < tg->lockidx;i ++) {\n printf(\"threadid : %ld, lockid: %ld\\n\", tg->locklist[i].id, tg->locklist[i].lock_id);\n }\n printf(\"---------------------\\n\\n\\n\");\n}\n\n//thread_id:线程id\n//lockaddr:线程即将要加的mutex id\nvoid lock_before(uint64 thread_id, uint64 lockaddr) {\n\n int idx = 0;\n // list\n for(idx = 0;idx < tg->lockidx;idx ++) {\n if ((tg->locklist[idx].lock_id == lockaddr)) {\n\n struct source_type from;\n from.id = thread_id;\n from.type = PROCESS;\n add_vertex(from);\n\n struct source_type to;\n to.id = tg->locklist[idx].id;\n tg->locklist[idx].degress++;\n to.type = PROCESS;\n add_vertex(to);\n \n if (!verify_edge(from, to)) {\n add_edge(from, to); // \n }\n }\n }\n}\n\nvoid lock_after(uint64 thread_id, uint64 lockaddr) {\n\n int idx = 0;\n if (-1 == (idx = search_lock(lockaddr))) { // 该锁还没被其他线程lock过\n\n int eidx = search_empty_lock(lockaddr);\n \n tg->locklist[eidx].id = thread_id;\n tg->locklist[eidx].lock_id = lockaddr;\n \n inc(&tg->lockidx, 1);//lock id下标增加+1\n \n } else {//idx不为-1,说明该锁被某个线程lock过,只是被该线程unlock了\n\n struct source_type from;\n from.id = thread_id;\n from.type = PROCESS;\n\n struct source_type to;\n to.id = tg->locklist[idx].id;\n tg->locklist[idx].degress --;\n to.type = PROCESS;\n\n if (verify_edge(from, to))//判断是否存在边,如果存在对应的边\n remove_edge(from, to);\n\n \n tg->locklist[idx].id = thread_id; //设置对应下标的锁的线程id为当前锁的线程id\n\n }\n \n}\n\nvoid unlock_after(uint64 thread_id, uint64 lockaddr) {\n\n int idx = search_lock(lockaddr);\n\n if (tg->locklist[idx].degress == 0) {\n tg->locklist[idx].id = 0;\n tg->locklist[idx].lock_id = 0;\n //inc(&tg->lockidx, -1);\n }\n \n}\n\nint pthread_mutex_lock(pthread_mutex_t *mutex) {\n\n pthread_t selfid = pthread_self(); //\n lock_before(selfid, (uint64)mutex);//加锁前操作\n pthread_mutex_lock_f(mutex);\n lock_after(selfid, (uint64)mutex);//加锁后操作\n\n}\n\nint pthread_mutex_unlock(pthread_mutex_t *mutex) {\n\n pthread_t selfid = pthread_self();\n pthread_mutex_unlock_f(mutex);\n unlock_after(selfid, (uint64)mutex);//解锁后操作\n}\n\nstatic int init_hook() {\n //锁住系统函数 pthread_mutex_lock\n pthread_mutex_lock_f = dlsym(RTLD_NEXT, \"pthread_mutex_lock\");\n pthread_mutex_unlock_f = dlsym(RTLD_NEXT, \"pthread_mutex_unlock\");\n}\n\n#if 1 //debug\npthread_mutex_t mutex_1 = PTHREAD_MUTEX_INITIALIZER;\npthread_mutex_t mutex_2 = PTHREAD_MUTEX_INITIALIZER;\npthread_mutex_t mutex_3 = PTHREAD_MUTEX_INITIALIZER;\npthread_mutex_t mutex_4 = PTHREAD_MUTEX_INITIALIZER;\n\nvoid *thread_rountine_1(void *args)\n{\n pthread_t selfid = pthread_self(); //\n\n printf(\"thread_routine 1 : %ld \\n\", selfid);\n \n pthread_mutex_lock(&mutex_1);//执行自定义的函数\n sleep(1);\n pthread_mutex_lock(&mutex_2);\n\n pthread_mutex_unlock(&mutex_2);\n pthread_mutex_unlock(&mutex_1);\n\n return (void *)(0);\n}\n\nvoid *thread_rountine_2(void *args)\n{\n pthread_t selfid = pthread_self(); //\n\n printf(\"thread_routine 2 : %ld \\n\", selfid);\n \n pthread_mutex_lock(&mutex_2);\n sleep(1);\n pthread_mutex_lock(&mutex_3);\n\n pthread_mutex_unlock(&mutex_3);\n pthread_mutex_unlock(&mutex_2);\n\n return (void *)(0);\n}\n\nvoid *thread_rountine_3(void *args)\n{\n pthread_t selfid = pthread_self(); //\n\n printf(\"thread_routine 3 : %ld \\n\", selfid);\n\n pthread_mutex_lock(&mutex_3);\n sleep(1);\n pthread_mutex_lock(&mutex_4);\n\n pthread_mutex_unlock(&mutex_4);\n pthread_mutex_unlock(&mutex_3);\n\n return (void *)(0);\n}\n\nvoid *thread_rountine_4(void *args)\n{\n pthread_t selfid = pthread_self(); //\n\n printf(\"thread_routine 4 : %ld \\n\", selfid);\n \n pthread_mutex_lock(&mutex_4);\n sleep(1);\n pthread_mutex_lock(&mutex_1);\n\n pthread_mutex_unlock(&mutex_1);\n pthread_mutex_unlock(&mutex_4);\n\n return (void *)(0);\n}\n\n\nint main()\n{\n init_hook();\n start_check();\n printf(\"start_check\\n\");\n pthread_t tid1, tid2, tid3, tid4;\n pthread_create(&tid1, NULL, thread_rountine_1, NULL);\n pthread_create(&tid2, NULL, thread_rountine_2, NULL);\n pthread_create(&tid3, NULL, thread_rountine_3, NULL);\n pthread_create(&tid4, NULL, thread_rountine_4, NULL);\n pthread_join(tid1, NULL);//等待线程1的结束\n pthread_join(tid2, NULL);\n pthread_join(tid3, NULL);\n pthread_join(tid4, NULL);\n return 0;\n}\n#endif\n```\n\n **运行** \n\ngcc -o deadlock deadlock.c -lpthread -ldl;\n\n### 2.读写锁 (Read-Write Lock)\n\n在 Linux 中,读写锁(read-write lock)是一种同步机制,用于保护共享资源,以允许多个线程同时读取资源,但 **在某个线程写入资源时阻止其他线程访问** 。读写锁是互斥锁的升级版, 在做读操作的时候可以提高程序的执行效率, **如果所有的线程都是做读操作, 那么读是并行的** , **但是使用互斥锁,读操作也是串行的** 。读写锁的优点在于,它能够在读操作频繁、写操作较少的场景下提高并发性能。\n\n在 Linux 中,读写锁通过pthread_rwlock_t 类型和相关函数来实现。常用函数包括:\n\n\n\n```\n// 初始化读写锁\nint pthread_rwlock_init(pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attr);\n// 销毁读写锁。\nint pthread_rwlock_destroy(pthread_rwlock_t *rwlock);\n// 获取读锁。\nint pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);\n// 获取写锁。\nint pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);\n// 释放读写锁\nint pthread_rwlock_unlock(pthread_rwlock_t *rwlock);\n```\n\n读写锁既可以锁定读操作,也可以锁定写操作,锁中记录了以下信息:\n\n读写锁的使用方式与互斥锁类似:找到共享资源,确定临界区,在临界区的开始位置加锁(读锁/写锁),在临界区的结束位置解锁。\n\n读写锁的特点:\n\n在程序中如果所有的线程都对共享资源进行写操作,使用读写锁没有优势,与互斥锁相同。如果程序中对共享资源的操作既有读也有写,并且 **读操作比写操作多,读写锁更具优势** 。因为读锁是共享的,能够提高读操作的并行性,从而提高性能。\n\n示例:读写锁在多线程环境下的使用,以保护共享资源 shared_resource。读线程可以并发地读取共享资源,而写线程需要独占访问共享资源。\n\n\n\n```\n#include \n#include \n#include \n\n// 声明一个读写锁\npthread_rwlock_t rwlock;\n// 共享资源\nint shared_resource = 0;\n\n// 读线程函数\nvoid* reader(void* arg) {\n for (int i = 0; i < 5; ++i) {\n // 加读锁\n pthread_rwlock_rdlock(&rwlock);\n // 读取共享资源并打印\n printf(\"Reader %ld: shared_resource = %d\\n\", (long)arg, shared_resource);\n // 解读锁\n pthread_rwlock_unlock(&rwlock);\n // 休眠1秒\n sleep(1);\n }\n return NULL;\n}\n\n// 写线程函数\nvoid* writer(void* arg) {\n for (int i = 0; i < 5; ++i) {\n // 加写锁\n pthread_rwlock_wrlock(&rwlock);\n // 修改共享资源并打印\n shared_resource++;\n printf(\"Writer %ld: shared_resource = %d\\n\", (long)arg, shared_resource);\n // 解写锁\n pthread_rwlock_unlock(&rwlock);\n // 休眠1秒\n sleep(1);\n }\n return NULL;\n}\n\nint main() {\n pthread_t readers[5], writers[2];\n\n // 初始化读写锁\n pthread_rwlock_init(&rwlock, NULL);\n\n // 创建5个读线程\n for (int i = 0; i < 5; ++i) {\n pthread_create(&readers[i], NULL, reader, (void*)i);\n }\n\n // 创建2个写线程\n for (int i = 0; i < 2; ++i) {\n pthread_create(&writers[i], NULL, writer, (void*)i);\n }\n\n // 等待所有读线程结束\n for (int i = 0; i < 5; ++i) {\n pthread_join(readers[i], NULL);\n }\n\n // 等待所有写线程结束\n for (int i = 0; i < 2; ++i) {\n pthread_join(writers[i], NULL);\n }\n\n // 销毁读写锁\n pthread_rwlock_destroy(&rwlock);\n\n return 0;\n}\n```\n\n \n\n### 3.条件变量 (Condition Variable)\n\n条件变量是一种线程同步机制,允许线程在某些条件满足前进行等待。条件变量通常与互斥锁一起使用,以避免竞态条件。条件变量的主要操作包括等待条件满足和通知其他等待线程条件已满足。\n\n一般情况下 **条件变量用于处理生产者和消费者模型,并且和互斥锁配合使用** 。条件变量类型对应的类型为pthread_cond_t。被条件变量阻塞的线程的线程信息会被记录到这个变量中,以便在解除阻塞的时候使用。\n\n\n\n```\n// 初始化条件变量\npthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr);\n// 销毁条件变量\npthread_cond_destroy(pthread_cond_t *cond);\n// 等待条件变量,调用此函数的线程将进入等待状态,并释放关联的互斥锁\npthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);\n// 通知至少一个等待条件变量的线程\npthread_cond_signal(pthread_cond_t *cond);\n// 通知所有等待条件变量的线程\npthread_cond_broadcast(pthread_cond_t *cond);\n```\n\n注意pthread_cond_wait通过函数原型可以看出,该函数在阻塞线程的时候,需要一个 **互斥锁参数** ,这个互斥锁主要功能是进行线程同步,让线程顺序进入临界区,避免出现数共享资源的数据混乱。该函数会对这个互斥锁做以下处理:\n\n以下是一个生产者-消费者问题的示例,使用条件变量来同步生产者和消费者线程。\n\n\n\n```\n#include \n#include \n#include \n#include \n\n#define BUFFER_SIZE 10\n\nint buffer[BUFFER_SIZE]; // 缓冲区\nint count = 0; // 当前缓冲区中的元素数量\n\npthread_mutex_t mutex; // 互斥锁\npthread_cond_t cond_producer; // 生产者条件变量\npthread_cond_t cond_consumer; // 消费者条件变量\n\n// 生产者线程函数\nvoid* producer(void* arg) {\n for (int i = 0; i < 20; ++i) {\n pthread_mutex_lock(&mutex); // 加锁\n\n // 如果缓冲区已满,等待生产者条件变量\n while (count == BUFFER_SIZE) {\n pthread_cond_wait(&cond_producer, &mutex);\n }\n\n // 生产数据\n buffer[count++] = i;\n printf(\"Produced: %d\\n\", i);\n\n // 通知消费者有数据可消费\n pthread_cond_signal(&cond_consumer);\n pthread_mutex_unlock(&mutex); // 解锁\n\n usleep(rand() % 100000); // 模拟生产时间\n }\n return NULL;\n}\n\n// 消费者线程函数\nvoid* consumer(void* arg) {\n for (int i = 0; i < 20; ++i) {\n pthread_mutex_lock(&mutex); // 加锁\n\n // 如果缓冲区为空,等待消费者条件变量\n while (count == 0) {\n pthread_cond_wait(&cond_consumer, &mutex);\n }\n\n // 消费数据\n int item = buffer[--count];\n printf(\"Consumed: %d\\n\", item);\n\n // 通知生产者可以继续生产\n pthread_cond_signal(&cond_producer);\n pthread_mutex_unlock(&mutex); // 解锁\n\n usleep(rand() % 100000); // 模拟消费时间\n }\n return NULL;\n}\n\nint main() {\n pthread_t prod, cons; // 生产者和消费者线程\n pthread_mutex_init(&mutex, NULL); // 初始化互斥锁\n pthread_cond_init(&cond_producer, NULL); // 初始化生产者条件变量\n pthread_cond_init(&cond_consumer, NULL); // 初始化消费者条件变量\n\n pthread_create(&prod, NULL, producer, NULL); // 创建生产者线程\n pthread_create(&cons, NULL, consumer, NULL); // 创建消费者线程\n\n pthread_join(prod, NULL); // 等待生产者线程完成\n pthread_join(cons, NULL); // 等待消费者线程完成\n\n pthread_mutex_destroy(&mutex); // 销毁互斥锁\n pthread_cond_destroy(&cond_producer); // 销毁生产者条件变量\n pthread_cond_destroy(&cond_consumer); // 销毁消费者条件变量\n\n return 0;\n}\n```\n\n### 4.信号量 (Semaphore)\n\n信号量 (Semaphore) 是一种用于进程同步的机制,是一种特殊的变量,主要用于多线程编程中来管理对共享资源的访问。信号量通过两个基本操作来实现同步控制:P操作(wait,等待)和V操作(signal,信号)。信号量可以分为两类:\n\n信号量和条件变量一样用于处理生产者和消费者模型,用于阻塞生产者线程或者消费者线程的运行。信号的类型为sem_t对应的头文件为:\n\n\n\n```\n#include \nsem_t sem;\n```\n\n信号量常用函数:\n\n\n\n```\n// 初始化信号量/信号灯\nint sem_init(sem_t *sem, int pshared, unsigned int value);\n// 资源释放, 线程销毁之后调用这个函数即可\n// 参数 sem 就是 sem_init() 的第一个参数 \nint sem_destroy(sem_t *sem);\n```\n\n\n\n```\n// 函数被调用sem中的资源就会被消耗1个, 资源数-1\nint sem_wait(sem_t *sem);\n```\n\n当线程调用这个函数,sem中的资源数>0,线程不会阻塞,线程会占用sem中的一个资源,因此 **资源数-1** ,直到sem中的资源数减为0时,资源被耗尽,因此线程也就被阻塞。\n\n\n\n```\n// 函数被调用sem中的资源就会被消耗1个, 资源数-1\nint sem_trywait(sem_t *sem);\n```\n\n当线程调用这个函数,并且sem中的资源数>0,线程不会阻塞,线程会占用sem中的一个资源,因此资源数-1,直到sem中的资源数减为0时,资源被耗尽,但是线程不会被阻塞,直接返回错误号, **因此可以在程序中添加判断分支,用于处理获取资源失败之后的情况** 。\n\n\n\n```\n/ 调用该函数给sem中的资源数+1\nint sem_post(sem_t *sem);\n```\n\n调用 **该函数会将sem中的资源数+1** ,如果有线程在调用sem_wait、sem_trywait、sem_timedwait时因为sem中的资源数为0被阻塞, **这时这些线程会解除阻塞** ,获取到资源之后继续向下运行。\n\n\n\n```\n// 查看信号量 sem 中的整形数的当前值, 这个值会被写入到sval指针对应的内存中\n// sval是一个传出参数\nint sem_getvalue(sem_t *sem, int *sval);\n```\n\n通过这个函数可以查看sem中现在拥有的资源个数,通过第二个参数sval将数据传出。\n\n下面是一个简单的例子,展示了如何在生产者-消费者问题中使用信号量进行同步控制。\n\n\n\n```\n#include \n#include \n#include \n#include \n#include \n\n#define BUFFER_SIZE 10\n\nint buffer[BUFFER_SIZE];\nint count = 0;\n\nsem_t empty; // 信号量,表示空缓冲区数量\nsem_t full; // 信号量,表示满缓冲区数量\npthread_mutex_t mutex; // 互斥锁,保护缓冲区\n\nvoid* producer(void* arg) {\n for (int i = 0; i < 20; ++i) {\n sem_wait(&empty); // P操作,等待空缓冲区\n pthread_mutex_lock(&mutex); // 加锁, 不要加到上一句,可能会产生死锁\n\n buffer[count++] = i; // 生产数据\n printf(\"Produced: %d\\n\", i);\n\n pthread_mutex_unlock(&mutex); // 解锁\n sem_post(&full); // V操作,增加满缓冲区数量\n\n usleep(rand() % 100000); // 模拟生产时间\n }\n return NULL;\n}\n\nvoid* consumer(void* arg) {\n for (int i = 0; i < 20; ++i) {\n sem_wait(&full); // P操作,等待满缓冲区\n pthread_mutex_lock(&mutex); // 加锁\n\n int item = buffer[--count]; // 消费数据\n printf(\"Consumed: %d\\n\", item);\n\n pthread_mutex_unlock(&mutex); // 解锁\n sem_post(&empty); // V操作,增加空缓冲区数量\n\n usleep(rand() % 100000); // 模拟消费时间\n }\n return NULL;\n}\n\nint main() {\n pthread_t prod, cons;\n\n sem_init(&empty, 0, BUFFER_SIZE); // 初始化空缓冲区信号量,值为BUFFER_SIZE\n sem_init(&full, 0, 0); // 初始化满缓冲区信号量,值为0\n pthread_mutex_init(&mutex, NULL); // 初始化互斥锁\n\n pthread_create(&prod, NULL, producer, NULL); // 创建生产者线程\n pthread_create(&cons, NULL, consumer, NULL); // 创建消费者线程\n\n pthread_join(prod, NULL); // 等待生产者线程完成\n pthread_join(cons, NULL); // 等待消费者线程完成\n\n sem_destroy(&empty); // 销毁信号量\n sem_destroy(&full); // 销毁信号量\n pthread_mutex_destroy(&mutex); // 销毁互斥锁\n\n return 0;\n}\n```\n\n \n\n\n \n\n
\n\n[https://zhuanlan.zhihu.com/p/5959929031](https://zhuanlan.zhihu.com/p/5959929031)
\n -->
0条评�?
全部评论

关于博主

an actually real engineer

通信工程专业毕业,7年开发经验

技术栈:

精通c/c++

精通golang

熟悉常见的脚本,js,lua,python,php

熟悉电路基础,嵌入式,单片机

耕耘领域:

服务端开发

嵌入式开发

git

>

gin接口代码CURD生成工具

sql ddl to struct and markdown,将sql表自动化生成代码内对应的结构体和markdown表格格式,节省宝贵的时间。

输入ddl:
输出代码:

qt .ui文件转css文件

duilib xml 自动生成绑定控件代码

协议调试器

基于lua虚拟机的的协议调试器软件 支持的协议有:

串口

tcp客户端/服务端

udp 组播/udp节点

tcp websocket 客户端/服务端

软件界面

使用例子: 通过脚本来获得接收到的数据并写入文件和展示在界面上

下载地址和源码

duilib版本源码 qt qml版本源码 二进制包

webrtc easy demo

webrtc c++ native 库 demo 实现功能:

基于QT

webrtc摄像头/桌面捕获功能

opengl渲染/多播放窗格管理

janus meeting room

下载地址和源码

源码 二进制包

wifi,蓝牙 - 无线开关

实现功能:

通过wifi/蓝牙实现远程开关电器或者其他电子设备

电路原理图:

实物图:

深度学习验证工具

vtk+pcl 点云编辑工具

实现功能:

1. 点云文件加载显示(.pcd obj stl)

2. 点云重建

3. 点云三角化

4. 点云缩放

下载地址:

源码 二进制包

虚拟示波器

硬件实物图:

实现原理

基本性能

采集频率: 取决于外部adc模块和ebaz4205矿板的以太网接口速率,最高可以达到100M/8 约为12.5MPS

上位机实现功能: 采集,显示波形,存储wave文件。

参数可运行时配置

上位机:

显示缓冲区大小可调

刷新率可调节

触发显示刷新可调节

进程守护工具

基本功能:

1. 守护进程,被守护程序崩溃后自动重启。

2. 进程输出获取,显示在编辑框中。

二进制包

openblt 烧录工具

基本功能:

1. 加载openblt 文件,下载到具有openblt bootloader 运行的单片机中。

二进制包

opencv 功能验证工具(开源项目二次开发)

基本功能:

1. 插件化图像处理流程,支持自定义图像处理流程。 2. 完善的日志和权限管理

二进制包

又一个modbus调试工具

最近混迹物联网企业,发现目前缺少一个简易可用的modbus调试工具,本软件旨在为开发者提供一个简单modbus测试工具。
主打一个代码简单易修改。
特点:

1. 基于QT5

2. 基于libmodbus

3. 三方库完全跨平台,linux/windows。

二进制包

屏幕录制工具

1. 基于QT5

2. 基于ffmpeg

3. 支持自定义录屏

源代码

开源plutosdr 板卡

1. 完全开源

2. 提高固件定制服务

3. 硬件售价450 手焊产量有线

测试数据

内部DDS回环测试

接收测试

外部发送500MHZ FM波形

硬件原理图

matlab测试

2TRX版本

大部分plutosdr应用场景都是讲plutosdr板卡作为射频收发器来使用。
实际上plutosdr板卡本身运行linux 操作系统。是具有一定脱机运算的能力。 对于一些微型频谱检测,简单射频信号收发等应用完全可以将应用层直接实现在板卡上
相较于通过网卡或者USB口传输具有更稳定,带宽更高等优点。
本开源板卡由于了SD卡启动,较原版pluto支持了自定义启动应用的功能。
提供了应用层开发SDK(编译器,buildroot文件系统)。
通过usb连接电脑,经过RNDIS驱动可以近似为通过网卡连接
(支持固件的开发定制)。

二次开发例子

``` all:
arm-linux-gnueabihf-gcc -mfloat-abi=hard --sysroot=/root/v0.32_2trx/buildroot/output/staging -std=gnu99 -g -o pluto_stream ad9361-iiostream.c -lpthread -liio -lm -Wall -Wextra -lrt
clean:
rm pluto_stream

bsdiff算法补丁生成器

1. 官方bsdiff算法例子自带bzip压缩方式

2. 本例子没有压缩,直接生成补丁文件

3. 图形化界面基于DUILIB

二进制文件

版面分析即分析出图片内的具体文件元素,如文档标题,文档内容,文档页码等,本工具基于cnstd模型

Base64 Image

. 闽ICP备19002644号