如何阻止多可执行程序并发访问.so库函数及共享配置文件?
根因分析
你使用的std::mutex属于进程内线程互斥锁,仅能同步同一进程下的不同线程,而你启动的exec1、exec2是完全独立的进程,且libCommon是静态链接到每个可执行程序的,每个进程都会持有独立的mutex副本,互不影响,因此锁完全不生效。
可选解决方案
方案1:修改启动脚本为串行启动(成本最低)
你当前的启动写法./exec1 & ./exec2会同时启动两个进程,直接调整为按序启动,每个进程启动完成后再启动下一个,从根源避免启动阶段的并发访问:
./exec1 & # 等待进程启动完成(可根据实际启动耗时调整等待时长,或者用pgrep判断进程状态) sleep 0.5 ./exec2 & sleep 0.5 # 其余进程依次类推
该方案无需修改代码,仅适用于配置文件仅在进程启动阶段读取的场景。
方案2:使用跨进程互斥锁
替换std::mutex为系统级跨进程互斥机制,Linux环境下可以用POSIX有名信号量实现:
// Common.cpp 新增头文件与逻辑 #include <semaphore.h> #include <fcntl.h> #include <sys/stat.h> namespace jsonFunctions { // 全局唯一的信号量名称,必须以/开头,长度不超过NAME_MAX const char* CONFIG_LOCK = "/json_config_global_lock"; namespace ROS { double readRosRate( configFiles::fileID configID ) { // 打开/创建有名信号量,初始值为1表示空闲 sem_t* lock = sem_open(CONFIG_LOCK, O_CREAT, 0666, 1); if (lock == SEM_FAILED) { // 自行补充错误处理逻辑 return 0.0; } // 加锁 sem_wait(lock); ConfigFile* desiredConfigFile = new ConfigFile( configID ); auto rosConfig = desiredConfigFile->parsedFile.get< jsonxx::Object >( "ROS" ); delete desiredConfigFile; // 解锁 sem_post(lock); sem_close(lock); // 注意:不要在这里调用sem_unlink,否则其他进程持有的锁会直接失效 return rosConfig.get< jsonxx::Number >( "rate" ); } } }
可以在系统全局停止脚本中执行sem_unlink("/json_config_global_lock")清理残留的信号量资源。
方案3:使用文件锁同步访问
基于操作系统的文件锁机制实现同步,兼容性更强,无需额外维护锁资源:
// Common.cpp 新增头文件,修改ConfigFile构造逻辑 #include <sys/file.h> #include <unistd.h> #include <fcntl.h> ConfigFile::ConfigFile( configFiles::fileID configID ) { const char* path = configFiles::filePaths.at(configID).c_str(); int fd = open(path, O_RDONLY); if (fd < 0) { // 补充文件打开失败处理逻辑 return; } // 加排他锁,确保同一时间只有一个进程访问文件 flock(fd, LOCK_EX); configFileFstream.open(path); if( configFileFstream.is_open() ) { parsedFile.parse( configFileFstream ); } // 关闭文件描述符会自动释放锁,也可以主动调用flock(fd, LOCK_UN)解锁 close(fd); }
如果配置文件只会被读取不会被修改,也可以把LOCK_EX换成LOCK_SH共享读锁,允许多个进程同时读取,性能更好。
方案4:预加载配置到共享内存
如果配置文件读取频次很高,可以在所有业务进程启动前,先启动一个预加载进程把配置内容读到共享内存中,所有业务进程直接从共享内存读取配置,完全避免文件并发访问问题,适合高性能要求场景。
内容的提问来源于stack exchange,提问作者Tomasz Małachowski
相关产品推荐
相关产品推荐

