Linux C多线程安全单例模式深度实践

article/2025/8/11 20:15:03

Linux C语言实现线程安全单例模式(含动态注册和复杂结构体)

    • 一、引言
    • 二、基本的单例实现方式
      • 1. 静态局部变量实现(C11线程安全)
      • 2. 双重检查锁定模式(Double-Checked Locking)
    • 三、封装复杂结构体(带文件输出的日志器)
      • 1. 头文件设计(logger.h)
      • 2. 实现文件(logger.c)
    • 四、多线程测试用例
    • 五、高级特性扩展
      • 1. 支持多日志输出通道
      • 2. 支持日志格式化器注册
      • 3. 支持异步日志写入
    • 六、性能优化建议
    • 七、错误处理与健壮性
      • 1、文件写入错误处理:
      • 2、内存分配检查:
      • 3、递归调用保护:
      • 4、信号安全处理:
    • 八、跨平台考虑
      • 1、路径分隔符:
      • 2、线程实现:
      • 3、时间函数:
    • 九、线程安全单例日志系统的逻辑图
      • 1、系统逻辑图
      • 2、关键模块交互流程图
      • 3、扩展设计:插件式架构
      • 4、性能优化对比表
      • 5、错误处理状态机
      • 6、跨平台适配层设计
      • 7、测试用例增强
    • 十、总结

一、引言

在系统软件或嵌入式开发中,我们常常需要某些模块在系统中仅有一个实例,并在多个线程中共享使用。这时候,就需要用到"单例模式"(Singleton Pattern)。

单例模式的核心目标是确保一个类只有一个实例,并提供一个全局访问点。在Linux C开发中,实现单例模式需要考虑以下几个关键点:

线程安全性
资源管理
可扩展性
性能影响

本文将深入探讨如何在Linux环境下用C语言实现一个线程安全的单例模式,包含动态注册功能和复杂结构体封装。

二、基本的单例实现方式

1. 静态局部变量实现(C11线程安全)


Logger* get_logger_instance() {static Logger instance = {0};  // C11标准保证线程安全的初始化return &instance;
}

优点:

简单直接
C11标准保证线程安全
自动管理生命周期

缺点:

不支持动态内存分配
初始化方式受限
难以实现复杂的初始化逻辑

2. 双重检查锁定模式(Double-Checked Locking)


Logger* get_logger_instance() {static Logger* instance = NULL;static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;if (instance == NULL) {pthread_mutex_lock(&mutex);if (instance == NULL) {instance = malloc(sizeof(Logger));// 初始化代码...}pthread_mutex_unlock(&mutex);}return instance;
}

优点:

支持动态内存分配
线程安全
延迟初始化

缺点:

代码复杂度稍高
需要手动管理资源

三、封装复杂结构体(带文件输出的日志器)

1. 头文件设计(logger.h)


#ifndef LOGGER_H
#define LOGGER_H#include <stddef.h>// 日志级别枚举
typedef enum {LOG_LEVEL_DEBUG,LOG_LEVEL_INFO,LOG_LEVEL_WARNING,LOG_LEVEL_ERROR,LOG_LEVEL_CRITICAL
} LogLevel;// 日志钩子函数类型
typedef void (*LogHook)(LogLevel level, const char* message, void* user_data);// 日志器配置结构体
typedef struct {const char* filename;LogLevel min_level;size_t max_file_size;int backup_count;
} LoggerConfig;// 日志器结构体
typedef struct Logger Logger;// 获取日志器实例
Logger* logger_get_instance(void);// 初始化日志器
int logger_initialize(const LoggerConfig* config);// 记录日志
void logger_log(LogLevel level, const char* format, ...);// 注册日志钩子
void logger_register_hook(LogHook hook, void* user_data);// 清理日志器
void logger_cleanup(void);#endif // LOGGER_H

2. 实现文件(logger.c)


#include "logger.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <pthread.h>
#include <stdarg.h>
#include <sys/stat.h>
#include <errno.h>// 日志器内部结构体
struct Logger {FILE* log_file;char* filename;pthread_mutex_t mutex;LogLevel min_level;size_t max_file_size;int backup_count;LogHook hook;void* hook_user_data;
};// 静态单例实例
static Logger* g_instance = NULL;
static pthread_mutex_t g_instance_mutex = PTHREAD_MUTEX_INITIALIZER;// 内部函数声明
static int rotate_log_file(Logger* logger);
static const char* get_level_string(LogLevel level);
static void write_log_header(FILE* file, LogLevel level);// 获取日志器实例
Logger* logger_get_instance(void) {if (g_instance == NULL) {pthread_mutex_lock(&g_instance_mutex);if (g_instance == NULL) {g_instance = calloc(1, sizeof(Logger));if (g_instance) {pthread_mutex_init(&g_instance->mutex, NULL);g_instance->min_level = LOG_LEVEL_INFO;g_instance->max_file_size = 10 * 1024 * 1024; // 默认10MBg_instance->backup_count = 5;}}pthread_mutex_unlock(&g_instance_mutex);}return g_instance;
}// 初始化日志器
int logger_initialize(const LoggerConfig* config) {Logger* logger = logger_get_instance();if (!logger || !config) return -1;pthread_mutex_lock(&logger->mutex);// 关闭现有文件if (logger->log_file) {fclose(logger->log_file);logger->log_file = NULL;}// 释放旧文件名if (logger->filename) {free(logger->filename);logger->filename = NULL;}// 设置新配置logger->min_level = config->min_level;logger->max_file_size = config->max_file_size;logger->backup_count = config->backup_count;if (config->filename) {logger->filename = strdup(config->filename);if (!logger->filename) {pthread_mutex_unlock(&logger->mutex);return -1;}logger->log_file = fopen(config->filename, "a");if (!logger->log_file) {free(logger->filename);logger->filename = NULL;pthread_mutex_unlock(&logger->mutex);return -1;}}pthread_mutex_unlock(&logger->mutex);return 0;
}// 记录日志
void logger_log(LogLevel level, const char* format, ...) {Logger* logger = logger_get_instance();if (!logger || level < logger->min_level) return;pthread_mutex_lock(&logger->mutex);// 检查是否需要滚动日志if (logger->log_file && logger->filename) {struct stat st;if (fstat(fileno(logger->log_file), &st) == 0 && (size_t)st.st_size >= logger->max_file_size) {rotate_log_file(logger);}}if (logger->log_file) {// 写入日志头write_log_header(logger->log_file, level);// 写入日志内容va_list args;va_start(args, format);vfprintf(logger->log_file, format, args);va_end(args);// 确保换行fputc('\n', logger->log_file);fflush(logger->log_file);}// 调用钩子函数if (logger->hook) {va_list args;va_start(args, format);char buffer[1024];vsnprintf(buffer, sizeof(buffer), format, args);va_end(args);logger->hook(level, buffer, logger->hook_user_data);}pthread_mutex_unlock(&logger->mutex);
}// 注册日志钩子
void logger_register_hook(LogHook hook, void* user_data) {Logger* logger = logger_get_instance();if (!logger) return;pthread_mutex_lock(&logger->mutex);logger->hook = hook;logger->hook_user_data = user_data;pthread_mutex_unlock(&logger->mutex);
}// 清理日志器
void logger_cleanup(void) {pthread_mutex_lock(&g_instance_mutex);if (g_instance) {pthread_mutex_lock(&g_instance->mutex);if (g_instance->log_file) {fclose(g_instance->log_file);g_instance->log_file = NULL;}if (g_instance->filename) {free(g_instance->filename);g_instance->filename = NULL;}pthread_mutex_unlock(&g_instance->mutex);pthread_mutex_destroy(&g_instance->mutex);free(g_instance);g_instance = NULL;}pthread_mutex_unlock(&g_instance_mutex);
}// 内部函数:滚动日志文件
static int rotate_log_file(Logger* logger) {if (!logger->filename || !logger->log_file) return -1;fclose(logger->log_file);logger->log_file = NULL;// 删除最旧的备份文件if (logger->backup_count > 0) {char old_path[PATH_MAX];snprintf(old_path, sizeof(old_path), "%s.%d", logger->filename, logger->backup_count);remove(old_path);// 重命名其他备份文件for (int i = logger->backup_count - 1; i >= 1; i--) {char src_path[PATH_MAX];char dst_path[PATH_MAX];snprintf(src_path, sizeof(src_path), "%s.%d", logger->filename, i);snprintf(dst_path, sizeof(dst_path), "%s.%d", logger->filename, i + 1);rename(src_path, dst_path);}// 重命名当前日志文件为.1char first_backup[PATH_MAX];snprintf(first_backup, sizeof(first_backup), "%s.1", logger->filename);rename(logger->filename, first_backup);}// 重新打开日志文件logger->log_file = fopen(logger->filename, "a");return logger->log_file ? 0 : -1;
}// 内部函数:获取日志级别字符串
static const char* get_level_string(LogLevel level) {switch (level) {case LOG_LEVEL_DEBUG:    return "DEBUG";case LOG_LEVEL_INFO:     return "INFO";case LOG_LEVEL_WARNING:  return "WARNING";case LOG_LEVEL_ERROR:    return "ERROR";case LOG_LEVEL_CRITICAL: return "CRITICAL";default:                 return "UNKNOWN";}
}// 内部函数:写入日志头
static void write_log_header(FILE* file, LogLevel level) {time_t now = time(NULL);struct tm tm_now;localtime_r(&now, &tm_now);char time_buf[64];strftime(time_buf, sizeof(time_buf), "%Y-%m-%d %H:%M:%S", &tm_now);fprintf(file, "[%s] %s - ", time_buf, get_level_string(level));
}

四、多线程测试用例


#include "logger.h"
#include <pthread.h>
#include <unistd.h>
#include <string.h>#define THREAD_COUNT 10
#define LOGS_PER_THREAD 20// 自定义日志钩子函数
void my_log_hook(LogLevel level, const char* message, void* user_data) {const char* prefix = (const char*)user_data;printf("[%s][Hook] %s: %s\n", prefix, get_level_string(level), message);
}// 线程函数
void* thread_func(void* arg) {int thread_num = *(int*)arg;char thread_name[16];snprintf(thread_name, sizeof(thread_name), "Thread%d", thread_num);for (int i = 0; i < LOGS_PER_THREAD; i++) {logger_log(LOG_LEVEL_INFO, "%s: Message %d", thread_name, i);usleep(10000); // 10ms}return NULL;
}int main() {// 初始化日志器LoggerConfig config = {.filename = "app.log",.min_level = LOG_LEVEL_DEBUG,.max_file_size = 1024, // 1KB for testing rotation.backup_count = 3};if (logger_initialize(&config) != 0) {fprintf(stderr, "Failed to initialize logger\n");return 1;}// 注册钩子函数logger_register_hook(my_log_hook, "MainHook");// 创建测试线程pthread_t threads[THREAD_COUNT];int thread_nums[THREAD_COUNT];for (int i = 0; i < THREAD_COUNT; i++) {thread_nums[i] = i;pthread_create(&threads[i], NULL, thread_func, &thread_nums[i]);}// 主线程也记录一些日志for (int i = 0; i < 5; i++) {logger_log(LOG_LEVEL_WARNING, "Main thread warning %d", i);usleep(50000); // 50ms}// 等待所有线程完成for (int i = 0; i < THREAD_COUNT; i++) {pthread_join(threads[i], NULL);}// 记录结束日志logger_log(LOG_LEVEL_INFO, "All threads completed");// 清理日志器logger_cleanup();return 0;
}

五、高级特性扩展

1. 支持多日志输出通道


typedef struct {FILE* file;LogLevel min_level;pthread_mutex_t mutex;
} LogChannel;struct Logger {LogChannel* channels;size_t channel_count;// 其他字段...
};int logger_add_channel(FILE* file, LogLevel min_level) {Logger* logger = logger_get_instance();if (!logger) return -1;pthread_mutex_lock(&logger->mutex);LogChannel* new_channels = realloc(logger->channels, (logger->channel_count + 1) * sizeof(LogChannel));if (!new_channels) {pthread_mutex_unlock(&logger->mutex);return -1;}logger->channels = new_channels;LogChannel* channel = &logger->channels[logger->channel_count++];channel->file = file;channel->min_level = min_level;pthread_mutex_init(&channel->mutex, NULL);pthread_mutex_unlock(&logger->mutex);return 0;
}

2. 支持日志格式化器注册


typedef void (*LogFormatter)(FILE* file, LogLevel level, const char* message);struct Logger {LogFormatter formatter;// 其他字段...
};void logger_set_formatter(LogFormatter formatter) {Logger* logger = logger_get_instance();if (!logger) return;pthread_mutex_lock(&logger->mutex);logger->formatter = formatter;pthread_mutex_unlock(&logger->mutex);
}// 在logger_log函数中使用:
if (logger->formatter) {logger->formatter(file, level, formatted_message);
} else {// 默认格式化
}

3. 支持异步日志写入


struct Logger {pthread_t async_thread;int async_running;pthread_cond_t async_cond;LogQueue* queue; // 需要实现一个线程安全的队列// 其他字段...
};void* async_log_thread(void* arg) {Logger* logger = (Logger*)arg;while (1) {pthread_mutex_lock(&logger->mutex);while (log_queue_empty(logger->queue) {if (!logger->async_running) {pthread_mutex_unlock(&logger->mutex);return NULL;}pthread_cond_wait(&logger->async_cond, &logger->mutex);}LogEntry entry = log_queue_pop(logger->queue);pthread_mutex_unlock(&logger->mutex);// 实际写入日志write_log_entry(&entry);}return NULL;
}int logger_start_async() {Logger* logger = logger_get_instance();if (!logger) return -1;pthread_mutex_lock(&logger->mutex);if (logger->async_running) {pthread_mutex_unlock(&logger->mutex);return 0;}logger->queue = log_queue_create();logger->async_running = 1;if (pthread_create(&logger->async_thread, NULL, async_log_thread, logger) != 0) {log_queue_destroy(logger->queue);logger->queue = NULL;logger->async_running = 0;pthread_mutex_unlock(&logger->mutex);return -1;}pthread_mutex_unlock(&logger->mutex);return 0;
}

六、性能优化建议

减少锁竞争:使用读写锁(pthread_rwlock_t)替代互斥锁实现细粒度锁策略批量写入:收集多条日志后一次性写入设置缓冲区大小阈值无锁队列:在异步日志模式下使用无锁队列减少线程间同步开销日志级别快速判断:
void logger_log(LogLevel level, const char* format, ...) {Logger* logger = logger_get_instance();if (!logger || level < logger->min_level) return;// ...}

热路径优化:

    将关键路径上的函数声明为inline避免在关键路径上分配内存

七、错误处理与健壮性

1、文件写入错误处理:


if (fprintf(logger->log_file, "...") < 0) {// 处理写入错误logger->write_errors++;if (logger->write_errors > MAX_WRITE_ERRORS) {// 尝试恢复或切换到备用日志}
}

2、内存分配检查:


Logger* logger = malloc(sizeof(Logger));
if (!logger) {// 记录错误或使用备用方案return NULL;
}

3、递归调用保护:


void logger_log(...) {static __thread int in_logger = 0;if (in_logger) return;in_logger = 1;// ...in_logger = 0;
}

4、信号安全处理:

void signal_handler(int sig) {// 使用异步信号安全函数char msg[] = "Received signal X\n";msg[16] = '0' + sig;write(STDERR_FILENO, msg, sizeof(msg));}

八、跨平台考虑

1、路径分隔符:


#if defined(_WIN32)
#define PATH_SEPARATOR '\\'
#else
#define PATH_SEPARATOR '/'
#endif

2、线程实现:


#ifdef _WIN32
#include <windows.h>
#define thread_handle HANDLE
#else
#include <pthread.h>
#define thread_handle pthread_t
#endif

3、时间函数:

#ifdef _WIN32// Windows时间函数实现#else// POSIX时间函数实现#endif

九、线程安全单例日志系统的逻辑图

采用分层架构和模块化思想:

1、系统逻辑图

+-------------------------------------------------------+
|                   Application Layer                   |
+-------------------------------------------------------+
| 调用 logger_log()  | 注册 hook  | 设置 formatter       |
+-------------------+------------+----------------------+↓
+-------------------------------------------------------+
|                  Logger Interface Layer               |
+-------------------------------------------------------+
| get_instance()  | 线程安全控制  | 多通道路由          |
| (双重检查锁定)    (pthread_mutex)  (channel选择器)     |
+-------------------------------------------------------+↓
+-------------------------------------------------------+
|                 Core Functionality Layer              |
+-------------------------------------------------------+
+------------------+ +------------------+ +-------------+
|   日志格式化模块   |   日志滚动模块     | 异步写入队列  |
| (时间戳/级别处理) | (大小检查/文件重命名)| (无锁队列)   |
+------------------+ +------------------+ +-------------+↓
+-------------------------------------------------------+
|                 Output Layer                          |
+-------------------------------------------------------+
+-------------+ +-------------+ +-------------+ +-------+
| 文件输出通道  | 网络输出通道  | 控制台输出通道 | Hook系统 |
| (带缓冲IO)   | (TCP/UDP)    | (ANSI颜色)    | (回调链)|
+-------------+ +-------------+ +-------------+ +-------+

2、关键模块交互流程图

在这里插入图片描述

3、扩展设计:插件式架构

  1. 动态加载输出插件
// plugin.h
typedef struct {const char* name;int (*init)(void* config);void (*write)(const char* msg);void (*cleanup)();
} LogPlugin;// 注册插件示例
void logger_register_plugin(LogPlugin* plugin) {pthread_mutex_lock(&g_plugin_mutex);g_plugins = realloc(g_plugins, (g_plugin_count+1)*sizeof(LogPlugin*));g_plugins[g_plugin_count++] = plugin;pthread_mutex_unlock(&g_plugin_mutex);
}
  1. 插件实现示例(Syslog输出)
// syslog_plugin.c
#include <syslog.h>static int syslog_init(void* config) {openlog("myapp", LOG_PID, LOG_USER);return 0;
}static void syslog_write(const char* msg) {syslog(LOG_INFO, "%s", msg);
}LogPlugin syslog_plugin = {.name = "syslog",.init = syslog_init,.write = syslog_write,.cleanup = closelog
};

4、性能优化对比表

优化策略	   	  吞吐量提升	 CPU占用降低		    实现复杂度			       适用场景
无锁队列	   		40-60%	   	30%				   高					高频日志(>10k条/)
批量写入	   		25-35%	   	20%				   中					磁盘IO瓶颈场景
读写锁	     	15-25%	   	10%				   低					读多写少场景
内存池预分配	  	10-15%	     5%				   中					避免内存碎片
热路径内联	  	 5-8%	     2%				   低					关键函数调用频繁

5、错误处理状态机

在这里插入图片描述

6、跨平台适配层设计

// platform.h
#ifdef _WIN32#define THREAD_HANDLE HANDLE#define MUTEX_TYPE CRITICAL_SECTION#define PATH_SEP '\\'
#else#define THREAD_HANDLE pthread_t#define MUTEX_TYPE pthread_mutex_t#define PATH_SEP '/'
#endif// 封装互斥锁操作
void mutex_lock(MUTEX_TYPE* m) {#ifdef _WIN32EnterCriticalSection(m);#elsepthread_mutex_lock(m);#endif
}

7、测试用例增强

1.并发压力测试

// test_concurrent.c
#define THREADS 100
#define LOGS_PER_THREAD 1000void* stress_test(void* arg) {for(int i=0; i<LOGS_PER_THREAD; i++){logger_log(LOG_DEBUG, "Thread %ld msg %d", (long)arg, i);}return NULL;
}int main() {LoggerConfig cfg = {.filename="stress.log", .max_file_size=GB(1)};logger_initialize(&cfg);pthread_t threads[THREADS];for(long i=0; i<THREADS; i++){pthread_create(&threads[i], NULL, stress_test, (void*)i);}// ...统计吞吐量...
}

2.故障注入测试

// 模拟磁盘满的情况
int mock_write(const char* msg) {static int fail_counter = 0;if(++fail_counter % 5 == 0) {errno = ENOSPC;return -1;}return real_write(msg);
}

十、总结

本文详细介绍了在Linux环境下使用C语言实现线程安全单例模式的完整方案,重点包括:

线程安全实现:通过互斥锁和双重检查锁定确保线程安全
复杂结构体封装:以日志器为例展示完整模块设计
动态注册机制:支持钩子函数和自定义格式化器
高级特性:日志滚动、异步写入、多通道支持等
性能优化:减少锁竞争、批量写入等技巧

最佳实践建议:

根据实际需求选择合适的单例实现方式
在性能关键场景考虑异步日志模式
实现完善的错误处理和恢复机制
设计良好的接口以支持未来扩展
在多线程环境中严格测试所有边界条件

这种单例模式实现方式适用于各种需要全局唯一实例的场景,如配置管理、设备驱动访问、服务代理等。


http://www.hkcw.cn/article/bhYsvbJbJq.shtml

相关文章

给在押人员递烤鸡榴莲 5名律师被罚 违规传递物品受惩

近日,厦门市司法局通报了五起律师违规会见案件,引发广泛关注。通报显示,2024年5月,高某某在广西横州市看守所会见在押人员时,将烤鸡肉、榴莲、棉花糖等食物传递给在押人员,并为同一监区的其他在押人员传递信件。2025年4月,市司法局给予高某某停止执业六个月的行政处罚。…

义乌288米超长“龙粽”登场 中外共庆端午情

你见过百米长的粽子吗?5月29日,城西街道在何斯路村举办了“丝路粽情 富路同行”百米长粽迎端午活动。活动中展示了一条总长288米、总重近2000公斤的巨型“龙粽”,吸引了超过5000名外国友人、游客和村民前来观看。当天上午9时,活动以东河小学学生的古风演奏开场。志成湖上,…

谷歌大变天 AI助理新时代

AI技术正在重塑科技巨头之间的竞争格局。谷歌近期频繁动作,试图重新确立其在行业中的领导地位。5月28日,谷歌宣布升级后的推理大模型Gemini 2.5 Pro版本正式上线,并迅速跃居LMSYS Arena榜单首位,得分1446分,远超OpenAI的o3和ChatGPT-4o。此前,LMSYS榜单产品之间的分值差通…

台湾青年因为肖战想去重庆 《藏海传》引发文化共鸣

近期,肖战主演的《藏海传》在台湾掀起追剧热潮,连续占据“台湾本日热播”榜首,并获得各大媒体好评。这部作品以中华文化为底色,用实力打破了“去中国化”的荒谬言论,让两岸同胞的文化共鸣如潮水般奔涌。《藏海传》的魅力在于对传统文化的精妙呈现。剧中展现了千年古城的建…

印度裔夫妇在华尔街办婚礼 金融街因盛大庆典停滞

当地时间5月29日,一场盛大的庆祝活动导致华尔街交通陷入瘫痪。当地媒体形容这是一场在曼哈顿缔结的联姻,让华尔街彻底停滞了。现场的DJ用手机记录下这一刻,并在社交媒体上发帖说:“我们为了一场400人的巴拉特庆祝活动关闭了华尔街。谁能想到呢?”巴拉特是南亚印度教婚礼中…

日本店铺玩具枪射出真子弹 意外揭露黑帮疑云

日本朝日电视台5月29日报道,松山市一家回收店铺最近经历了一场惊险事件。店员在整理一箱旧“玩具枪”时,突然有一把枪射出子弹,打穿了店内隔板。店员随后发现弹夹和子弹都是真的,立刻报警。上周,一名顾客将数十件“玩具枪”和“模型刀”送到店里,称这些是亲戚的遗物。警方…

2天之内十余家券商聚焦“稳定币” 投资机遇受追捧

几乎在一夜之间,“稳定币”突然火了。5月29日到30日,短短两天内就有多达十余场以稳定币为关键词的券商电话会扎堆举行,涉及业内十多家券商。这几天,多只稳定币概念股也接连有强势表现。这股热潮的背后是事件催化剂的发酵。近日,香港特别行政区立法会通过《稳定币条例草案》…

文旅局调查男子掉进兵马俑坑 游客破坏文物引发关注

5月30日下午6时许,陕西秦始皇兵马俑博物馆发生了一起意外事件。在兵马俑3号坑,一名男子突然跳入俑坑,并推倒了两尊兵马俑。据现场目击者小林回忆,当时他在导游的带领下前往3号坑,刚进入就看到一名男子跳入俑坑,先是跳到中间一层,随后又跳到俑坑底部。周围的人纷纷大喊“…

【Web应用】若依框架:基础篇08功能详解-定时任务

文章目录 ⭐前言⭐一、讲解过程⭐二、动手实操⭐总结 标题详情作者JosieBook头衔CSDN博客专家资格、阿里云社区专家博主、软件设计工程师博客内容开源、框架、软件工程、全栈&#xff08;,NET/Java/Python/C&#xff09;、数据库、操作系统、大数据、人工智能、工控、网络、程序…

尼日利亚洪水已造成至少110人死亡 雨季灾害频发

尼日利亚尼日尔州应急管理局官员29日表示,该国中部城市莫夸遭遇强降雨,至少25人遇难。28日晚的暴雨引发洪水,莫夸市至少50栋民房被冲走或淹没,另有10人失踪。潜水员和志愿者救起了一名妇女和她的两个孩子,他们因受伤和休克正在医院接受治疗。尼日利亚每年在5月至11月的雨季…

卢东亮任山西省委副书记 新职任命公布

卢东亮同志任山西省委副书记。他出生于1973年12月,汉族,拥有大学学历和经济学学士学位,是中共党员。目前,他还担任二十届中央候补委员、山西省委常委、常务副省长、省政府党组副书记、省委军民融合办主任以及省委金融办主任和省委金融工委书记(兼)等职务。责任编辑:0764…

俄罗斯黑熊跨境游到中国境内 村民被提醒注意安全

5月29日,黑龙江省鹤岗市萝北县有渔民在下江作业时,发现一只黑熊横渡黑龙江,从俄罗斯游到了中国境内。这只黑熊上岸后消失在了山林中。视频内容显示,这只黑熊出现在萝北县太平沟乡太平沟村附近,在黑龙江里游泳的样子显得十分迅捷。看到渔民驾船靠近,它原地用熊掌拍击水面停…

艺人罗家英自曝第四次患癌 乐观面对余生

艺人罗家英日前透露,他第四次患癌,最多剩下9年寿命。他表示不会选择化疗和电疗,希望以舒适的方式度过余生。现年78岁的罗家英曾在2004年、2014年两度患上肝癌,2019年又被发现患有前列腺癌,但每次都成功抗癌。近年来,他积极运动并保持健康饮食。罗家英原名罗行堂,1946年9…

中国女孩在哈佛毕业典礼上发表演讲 多元化与同理心的呼唤

5月30日,一则关于“哈佛毕业礼,中国学生发声”的视频在网络上引起广泛关注。视频展示了5月29日哈佛大学毕业典礼上,身着中国传统服饰的中国籍学生蒋雨融代表毕业生演讲的情景。她强调了保持多元化和国际化的重要性,并呼吁同学们保持同理心与善意。演讲结束后,全场观众报以…

男子被捕后造假借条起诉妻子 虚假诉讼罪判刑

刘颖在被丈夫李某涛殴打导致4根肋骨骨折后报警,并向法院起诉离婚。与此同时,李某涛的弟弟李某溢也起诉刘颖,要求她偿还三百多万元的“债务”。几年来,刘颖和丈夫之间的纠纷涉及了离婚案、故意伤害案和民间借贷案。李某涛及其弟弟李某溢、弟媳张某芳因虚假诉讼罪被判刑。一审…

陈雨菲用胜利回应质疑 终结安洗莹27连胜

在5月30日举行的新加坡公开赛女单四分之一决赛中,陈雨菲以21比13、21比16直落两局击败安洗莹,闯入四强,终结了韩国名将的27连胜纪录,同时也成就了自己本赛季在国际赛场的20连胜。新加坡公开赛作为世界羽联超级750赛事,吸引了众多顶尖选手参赛。除了印尼一姐玛丽斯卡外,世…

【JSON-to-Video】添加背景图与动效技巧

在JSON转视频的过程中&#xff0c;添加背景图片和动效能够极大提升视频的视觉效果。 今天就来学习如何通过设置相关字段实现这一操作&#xff0c;让你的视频脱颖而出。 JSON转视频教程&#xff0c;添加背景图与动效技巧 1. 设置bgImg&#xff08;Object&#xff09;字段 {&qu…

宇树科技新海报:新机器人即将亮相 26关节自由度揭秘

每经快讯,5月30日,宇树科技官方微信公众号发布了海报,展现一个新机器人剪影,并配文“26 joint DOF(6*2+2+5*2+2)”。每日经济新闻责任编辑:0764

专访《藏海传》“最强辅助”梁超 揭秘幕后故事

古装剧《藏海传》在央视热播,掀起了一波观剧热潮。剧中,“藏海”的师父“高明”被誉为“最强辅助”,受到广泛关注。5月29日,梁超接受了采访,透露在后续剧情中,他帮助“藏海”完成了复仇的关键一步。谈及与肖战的合作,梁超表示,肖战具备了艺术家的所有条件。由郑晓龙执导…

Linux 内核是如何感知到硬件上的 NUMA 信息的?

大家好&#xff0c;我是飞哥&#xff01; 在 Linux 程序运行过程中&#xff0c;有一个对性能影响较大的特性&#xff0c;那就是 NUMA。在不少公司中&#xff0c;都通过 numactl 等命令对运行的服务进行了 NUMA 绑定&#xff0c;进而提高程序的运行性能。 那么我们今天来深入了解…