我在postgresql中写了一个函数。这是我的初始化函数:
void _PG_init(){
int line = 0, errcode2 = 0;
char buf[1024], db_log[1024];
dbglog("first call\n");
l = (local_t*)palloc(sizeof(local_t));
if(!l) die(ERROR_NOMEM);
dbglog("first palloc local_t\n");
memset(l, 0, sizeof(local_t));
session_init_lock = 0;
sprintf(buf, "%s/" PREFIX "/privacyprot.log", getenv("HOME"));
l->logfile = fopen(buf, "a+");
if(!(l->logfile)) die(ERROR_NOMEM);
l->begin_time = time(NULL);
return;
}
我知道首次加载此lib时,会立即调用_PG_init,但是,“first call”日志会被打印两次。如何解决这个问题,我只想要一个单一的线程。
答案 0 :(得分:3)
由于您的测试方式,您可能会看到它被调用两次。
每个后端进程调用一次,当它通过显式LOAD
来电,local_preload_libraries
或LANGUAGE c
调用后加载到该进程中引用该共享库的函数。
是的,按程序进行。 PostgreSQL是一个多进程架构,每个进程有一个fork()
个连接。每个后端都可以读取postmaster内存,因为fork()
使其复制写入,但是当写入将页面复制到进程的私有地址空间时,进程无法通过写入全局变量(如多线程程序)进行通信。相反,它们使用显式分配的共享内存段进行通这是一个默认的无共享模型,而不是多线程编程的默认共享模型。
如果您希望PG_init
完全被调用一次,则必须使用shared_preload_libraries
使邮件管理员在启动时加载您的库,然后在后端获取fork()
之前。在这种情况下,它无法访问数据库或所有常用设施,因此它主要注册挂钩和回调,请求共享内存段和锁定分配,然后继续正常启动。您也可以在此阶段注册后台工作进程。
通过在postmaster启动期间请求自己的共享内存,您的扩展可以使用此内存,以及PostgreSQL提供的其他IPC机制(如锁和锁存器),以便在后端之间进行通信。
您将在contrib/
目录中找到扩展中基本使用共享内存的一些示例。
请参阅:
以及从那里链接的各种资源。