- 浏览: 982484 次
- 性别:
- 来自: 广州
最新评论
-
qingchuwudi:
有用,非常感谢!
erlang进程的优先级 -
zfjdiamond:
你好 这条命令 在那里输入??
你们有yum 我有LuaRocks -
simsunny22:
这个是在linux下运行的吧,在window下怎么运行escr ...
escript的高级特性 -
mozhenghua:
http://www.erlang.org/doc/apps/ ...
mnesia 分布协调的几个细节 -
fxltsbl:
A new record of 108000 HTTP req ...
Haproxy 1.4-dev2: barrier of 100k HTTP req/s crossed
erlang通过port来spawn外部程序 重定向外部程序的stdin, stdout到一对pipe行通信的,利用poll来检测外部程序的读写事件。但是如果外部程序退出的话,erts如何知道并且加以处理的呢?
erts运行的时候会初始化smp_sig_notify,开启一个信号处理线程,在这个线程里面做具体的信号处理。
static void
init_smp_sig_notify(void)
{
erts_smp_thr_opts_t thr_opts = ERTS_SMP_THR_OPTS_DEFAULT_INITER;
thr_opts.detached = 1;
if (pipe(sig_notify_fds) < 0) {
erl_exit(ERTS_ABORT_EXIT,
"Failed to create signal-dispatcher pipe: %s (%d)\n",
erl_errno_id(errno),
errno);
}
/* Start signal handler thread */
erts_smp_thr_create(&sig_dispatcher_tid,
signal_dispatcher_thread_func,
NULL,
&thr_opts);
}
static void *
signal_dispatcher_thread_func(void *unused)
{
int initialized = 0;
#if !CHLDWTHR
int notify_check_children = 0;
#endif
#ifdef ERTS_ENABLE_LOCK_CHECK
erts_lc_set_thread_name("signal_dispatcher");
#endif
erts_thread_init_fp_exception();
while (1) {
char buf[32];
int res, i;
/* Block on read() waiting for a signal notification to arrive... */
res = read(sig_notify_fds[0], (void *) &buf[0], 32);
if (res < 0) {
if (errno == EINTR)
continue;
erl_exit(ERTS_ABORT_EXIT,
"signal-dispatcher thread got unexpected error: %s (%d)\n",
erl_errno_id(errno),
errno);
}
for (i = 0; i < res; i++) {
/*
* NOTE 1: The signal dispatcher thread should not do work
* that takes a substantial amount of time (except
* perhaps in test and debug builds). It needs to
* be responsive, i.e, it should only dispatch work
* to other threads.
*
* NOTE 2: The signal dispatcher thread is not a blockable
* thread (i.e., it hasn't called
* erts_register_blockable_thread()). This is
* intentional. We want to be able to interrupt
* writing of a crash dump by hitting C-c twice.
* Since it isn't a blockable thread it is important
* that it doesn't change the state of any data that
* a blocking thread expects to have exclusive access
* to (unless the signal dispatcher itself explicitly
* is blocking all blockable threads).
*/
switch (buf[i]) {
case 0: /* Emulator initialized */
initialized = 1;
#if !CHLDWTHR
if (!notify_check_children)
#endif
break;
#if !CHLDWTHR
case 'C': /* SIGCHLD */
if (initialized)
erts_smp_notify_check_children_needed();
else
notify_check_children = 1;
break;
#endif
case 'I': /* SIGINT */
break_requested();
break;
case 'Q': /* SIGQUIT */
quit_requested();
break;
case '1': /* SIGUSR1 */
sigusr1_exit();
break;
#ifdef QUANTIFY
case '2': /* SIGUSR2 */
quantify_save_data(); /* Might take a substantial amount of
time, but this is a test/debug
build */
break;
#endif
default:
erl_exit(ERTS_ABORT_EXIT,
"signal-dispatcher thread received unknown "
"signal notification: '%c'\n",
buf[i]);
}
}
ERTS_SMP_LC_ASSERT(!ERTS_LC_IS_BLOCKING);
}
return NULL;
}
void
erts_sys_main_thread(void)
{
/* Become signal receiver thread... */
#ifdef ERTS_ENABLE_LOCK_CHECK
erts_lc_set_thread_name("signal_receiver");
#endif
smp_sig_notify(0); /* Notify initialized */
while (1) {
/* Wait for a signal to arrive... */
#ifdef DEBUG
int res =
#else
(void)
#endif
select(0, NULL, NULL, NULL, NULL);
ASSERT(res < 0);
ASSERT(errno == EINTR);
}
}
因为外部的程序是fork exec来执行的,所以退出的时候erts进程就会受到SIGCHLD信号。
static int spawn_init()
{
...
sys_sigset(SIGCHLD, onchld); /* Reap children */
...
}
onchld就会被调用
static RETSIGTYPE onchld(int signum)
{
#if CHLDWTHR
ASSERT(0); /* We should *never* catch a SIGCHLD signal */
#elif defined(ERTS_SMP)
smp_sig_notify('C');
#else
children_died = 1;
ERTS_CHK_IO_INTR(1); /* Make sure we don't sleep in poll */
#endif
}
static void
smp_sig_notify(char c)
{
int res;
do {
/* write() is async-signal safe (according to posix) */
res = write(sig_notify_fds[1], &c, 1);
} while (res < 0 && errno == EINTR);
if (res != 1) {
char msg[] =
"smp_sig_notify(): Failed to notify signal-dispatcher thread "
"about received signal";
(void) write(2, msg, sizeof(msg));
abort();
}
}
于是erts_smp_notify_check_children_needed()被调用。
void
erts_smp_notify_check_children_needed(void)
{
ErtsSchedulerData *esdp;
erts_smp_sched_lock();
for (esdp = schedulers; esdp; esdp = esdp->next)
esdp->check_children = 1;
if (block_multi_scheduling) {
/* Also blocked schedulers need to check children */
erts_smp_mtx_lock(&msched_blk_mtx);
for (esdp = schedulers; esdp; esdp = esdp->next)
esdp->blocked_check_children = 1;
erts_smp_cnd_broadcast(&msched_blk_cnd);
erts_smp_mtx_unlock(&msched_blk_mtx);
}
wake_all_schedulers();
erts_smp_sched_unlock();
}
这个函数设置调度器的check_children的标志 并且唤醒所有的调度器。
调度器的入口process_main我们来看下如何处理的:
Process *schedule(Process *p, int calls)
{
...
if (esdp->check_children) {
esdp->check_children = 0;
erts_smp_sched_unlock();
erts_check_children();
erts_smp_sched_lock();
}
...
}
调用erts_check_children。
void
erts_check_children(void)
{
(void) check_children();
}
static int check_children(void)
{
int res = 0;
int pid;
int status;
#ifndef ERTS_SMP
if (children_died)
#endif
{
sys_sigblock(SIGCHLD);
CHLD_STAT_LOCK;
while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
note_child_death(pid, status);
#ifndef ERTS_SMP
children_died = 0;
#endif
CHLD_STAT_UNLOCK;
sys_sigrelease(SIGCHLD);
res = 1;
}
return res;
}
static void note_child_death(int pid, int status)
{
ErtsSysReportExit **repp = &report_exit_list;
ErtsSysReportExit *rep = report_exit_list;
while (rep) {
if (pid == rep->pid) {
*repp = rep->next;
ERTS_REPORT_EXIT_STATUS(rep, status);
break;
}
repp = &rep->next;
rep = rep->next;
}
}
static ERTS_INLINE void
report_exit_status(ErtsSysReportExit *rep, int status)
{
Port *pp;
#ifdef ERTS_SMP
CHLD_STAT_UNLOCK;
#endif
pp = erts_id2port_sflgs(rep->port,
NULL,
0,
ERTS_PORT_SFLGS_INVALID_DRIVER_LOOKUP);
#ifdef ERTS_SMP
CHLD_STAT_LOCK;
#endif
if (pp) {
if (rep->ifd >= 0) {
driver_data[rep->ifd].alive = 0;
driver_data[rep->ifd].status = status;
(void) driver_select((ErlDrvPort) internal_port_index(pp->id),
rep->ifd,
DO_READ,
1);
}
if (rep->ofd >= 0) {
driver_data[rep->ofd].alive = 0;
driver_data[rep->ofd].status = status;
(void) driver_select((ErlDrvPort) internal_port_index(pp->id),
rep->ofd,
DO_WRITE,
1); }
erts_port_release(pp);
}
erts_free(ERTS_ALC_T_PRT_REP_EXIT, rep);
}
移除对该port的监视 销毁port.
static void ready_input(ErlDrvData e, ErlDrvEvent ready_fd)
{
...
res = read(ready_fd, read_buf, ERTS_SYS_READ_BUF_SZ);
if (res < 0) {
if ((errno != EINTR) && (errno != ERRNO_BLOCK))
port_inp_failure(port_num, ready_fd, res);
}
else if (res == 0)
port_inp_failure(port_num, ready_fd, res);
else
driver_output(port_num, (char*) read_buf, res);
erts_free(ERTS_ALC_T_SYS_READ_BUF, (void *) read_buf);
}....
}
static int port_inp_failure(int port_num, int ready_fd, int res)
/* Result: 0 (eof) or -1 (error) */
{
int err = errno;
ASSERT(res <= 0);
(void) driver_select(port_num, ready_fd, ERL_DRV_READ|ERL_DRV_WRITE, 0);
clear_fd_data(ready_fd);
if (res == 0) {
if (driver_data[ready_fd].report_exit) {
CHLD_STAT_LOCK;
if (driver_data[ready_fd].alive) {
/*
* We have eof and want to report exit status, but the process
* hasn't exited yet. When it does report_exit_status() will
* driver_select() this fd which will make sure that we get
* back here with driver_data[ready_fd].alive == 0 and
* driver_data[ready_fd].status set.
*/
CHLD_STAT_UNLOCK;
return 0;
}
else {
int status = driver_data[ready_fd].status;
CHLD_STAT_UNLOCK;
/* We need not be prepared for stopped/continued processes. */
if (WIFSIGNALED(status))
status = 128 + WTERMSIG(status);
else
status = WEXITSTATUS(status);
driver_report_exit(driver_data[ready_fd].port_num, status); }
}
driver_failure_eof(port_num);
} else {
driver_failure_posix(port_num, err);
}
return 0;
}
void driver_report_exit(int ix, int status)
{
Port* prt = erts_drvport2port(ix);
Eterm* hp;
Eterm tuple;
Process *rp;
Eterm pid;
ErlHeapFragment *bp = NULL;
ErlOffHeap *ohp;
ErtsProcLocks rp_locks = 0;
ERTS_SMP_CHK_NO_PROC_LOCKS;
ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt));
pid = prt->connected;
ASSERT(is_internal_pid(pid));
rp = erts_pid2proc_opt(NULL, 0, pid, 0, ERTS_P2P_FLG_SMP_INC_REFC);
if (!rp)
return;
hp = erts_alloc_message_heap(3+3, &bp, &ohp, rp, &rp_locks);
tuple = TUPLE2(hp, am_exit_status, make_small(status));
hp += 3;
tuple = TUPLE2(hp, prt->id, tuple); erts_queue_message(rp, &rp_locks, bp, tuple, am_undefined);
erts_smp_proc_unlock(rp, rp_locks);
erts_smp_proc_dec_refc(rp);
}
于是我们收到{Port, {exit_staus, Staus}}事件。
有点复杂吧,不过挺优雅的。记住信号处理函数里面不能做太耗时和调用有害的api。还有会有大量的退出事件发生,让调度器来调度这个事情比较公平,避免系统在处理退出处理上投入!
erts运行的时候会初始化smp_sig_notify,开启一个信号处理线程,在这个线程里面做具体的信号处理。
static void
init_smp_sig_notify(void)
{
erts_smp_thr_opts_t thr_opts = ERTS_SMP_THR_OPTS_DEFAULT_INITER;
thr_opts.detached = 1;
if (pipe(sig_notify_fds) < 0) {
erl_exit(ERTS_ABORT_EXIT,
"Failed to create signal-dispatcher pipe: %s (%d)\n",
erl_errno_id(errno),
errno);
}
/* Start signal handler thread */
erts_smp_thr_create(&sig_dispatcher_tid,
signal_dispatcher_thread_func,
NULL,
&thr_opts);
}
static void *
signal_dispatcher_thread_func(void *unused)
{
int initialized = 0;
#if !CHLDWTHR
int notify_check_children = 0;
#endif
#ifdef ERTS_ENABLE_LOCK_CHECK
erts_lc_set_thread_name("signal_dispatcher");
#endif
erts_thread_init_fp_exception();
while (1) {
char buf[32];
int res, i;
/* Block on read() waiting for a signal notification to arrive... */
res = read(sig_notify_fds[0], (void *) &buf[0], 32);
if (res < 0) {
if (errno == EINTR)
continue;
erl_exit(ERTS_ABORT_EXIT,
"signal-dispatcher thread got unexpected error: %s (%d)\n",
erl_errno_id(errno),
errno);
}
for (i = 0; i < res; i++) {
/*
* NOTE 1: The signal dispatcher thread should not do work
* that takes a substantial amount of time (except
* perhaps in test and debug builds). It needs to
* be responsive, i.e, it should only dispatch work
* to other threads.
*
* NOTE 2: The signal dispatcher thread is not a blockable
* thread (i.e., it hasn't called
* erts_register_blockable_thread()). This is
* intentional. We want to be able to interrupt
* writing of a crash dump by hitting C-c twice.
* Since it isn't a blockable thread it is important
* that it doesn't change the state of any data that
* a blocking thread expects to have exclusive access
* to (unless the signal dispatcher itself explicitly
* is blocking all blockable threads).
*/
switch (buf[i]) {
case 0: /* Emulator initialized */
initialized = 1;
#if !CHLDWTHR
if (!notify_check_children)
#endif
break;
#if !CHLDWTHR
case 'C': /* SIGCHLD */
if (initialized)
erts_smp_notify_check_children_needed();
else
notify_check_children = 1;
break;
#endif
case 'I': /* SIGINT */
break_requested();
break;
case 'Q': /* SIGQUIT */
quit_requested();
break;
case '1': /* SIGUSR1 */
sigusr1_exit();
break;
#ifdef QUANTIFY
case '2': /* SIGUSR2 */
quantify_save_data(); /* Might take a substantial amount of
time, but this is a test/debug
build */
break;
#endif
default:
erl_exit(ERTS_ABORT_EXIT,
"signal-dispatcher thread received unknown "
"signal notification: '%c'\n",
buf[i]);
}
}
ERTS_SMP_LC_ASSERT(!ERTS_LC_IS_BLOCKING);
}
return NULL;
}
void
erts_sys_main_thread(void)
{
/* Become signal receiver thread... */
#ifdef ERTS_ENABLE_LOCK_CHECK
erts_lc_set_thread_name("signal_receiver");
#endif
smp_sig_notify(0); /* Notify initialized */
while (1) {
/* Wait for a signal to arrive... */
#ifdef DEBUG
int res =
#else
(void)
#endif
select(0, NULL, NULL, NULL, NULL);
ASSERT(res < 0);
ASSERT(errno == EINTR);
}
}
因为外部的程序是fork exec来执行的,所以退出的时候erts进程就会受到SIGCHLD信号。
static int spawn_init()
{
...
sys_sigset(SIGCHLD, onchld); /* Reap children */
...
}
onchld就会被调用
static RETSIGTYPE onchld(int signum)
{
#if CHLDWTHR
ASSERT(0); /* We should *never* catch a SIGCHLD signal */
#elif defined(ERTS_SMP)
smp_sig_notify('C');
#else
children_died = 1;
ERTS_CHK_IO_INTR(1); /* Make sure we don't sleep in poll */
#endif
}
static void
smp_sig_notify(char c)
{
int res;
do {
/* write() is async-signal safe (according to posix) */
res = write(sig_notify_fds[1], &c, 1);
} while (res < 0 && errno == EINTR);
if (res != 1) {
char msg[] =
"smp_sig_notify(): Failed to notify signal-dispatcher thread "
"about received signal";
(void) write(2, msg, sizeof(msg));
abort();
}
}
于是erts_smp_notify_check_children_needed()被调用。
void
erts_smp_notify_check_children_needed(void)
{
ErtsSchedulerData *esdp;
erts_smp_sched_lock();
for (esdp = schedulers; esdp; esdp = esdp->next)
esdp->check_children = 1;
if (block_multi_scheduling) {
/* Also blocked schedulers need to check children */
erts_smp_mtx_lock(&msched_blk_mtx);
for (esdp = schedulers; esdp; esdp = esdp->next)
esdp->blocked_check_children = 1;
erts_smp_cnd_broadcast(&msched_blk_cnd);
erts_smp_mtx_unlock(&msched_blk_mtx);
}
wake_all_schedulers();
erts_smp_sched_unlock();
}
这个函数设置调度器的check_children的标志 并且唤醒所有的调度器。
调度器的入口process_main我们来看下如何处理的:
Process *schedule(Process *p, int calls)
{
...
if (esdp->check_children) {
esdp->check_children = 0;
erts_smp_sched_unlock();
erts_check_children();
erts_smp_sched_lock();
}
...
}
调用erts_check_children。
void
erts_check_children(void)
{
(void) check_children();
}
static int check_children(void)
{
int res = 0;
int pid;
int status;
#ifndef ERTS_SMP
if (children_died)
#endif
{
sys_sigblock(SIGCHLD);
CHLD_STAT_LOCK;
while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
note_child_death(pid, status);
#ifndef ERTS_SMP
children_died = 0;
#endif
CHLD_STAT_UNLOCK;
sys_sigrelease(SIGCHLD);
res = 1;
}
return res;
}
static void note_child_death(int pid, int status)
{
ErtsSysReportExit **repp = &report_exit_list;
ErtsSysReportExit *rep = report_exit_list;
while (rep) {
if (pid == rep->pid) {
*repp = rep->next;
ERTS_REPORT_EXIT_STATUS(rep, status);
break;
}
repp = &rep->next;
rep = rep->next;
}
}
static ERTS_INLINE void
report_exit_status(ErtsSysReportExit *rep, int status)
{
Port *pp;
#ifdef ERTS_SMP
CHLD_STAT_UNLOCK;
#endif
pp = erts_id2port_sflgs(rep->port,
NULL,
0,
ERTS_PORT_SFLGS_INVALID_DRIVER_LOOKUP);
#ifdef ERTS_SMP
CHLD_STAT_LOCK;
#endif
if (pp) {
if (rep->ifd >= 0) {
driver_data[rep->ifd].alive = 0;
driver_data[rep->ifd].status = status;
(void) driver_select((ErlDrvPort) internal_port_index(pp->id),
rep->ifd,
DO_READ,
1);
}
if (rep->ofd >= 0) {
driver_data[rep->ofd].alive = 0;
driver_data[rep->ofd].status = status;
(void) driver_select((ErlDrvPort) internal_port_index(pp->id),
rep->ofd,
DO_WRITE,
1); }
erts_port_release(pp);
}
erts_free(ERTS_ALC_T_PRT_REP_EXIT, rep);
}
移除对该port的监视 销毁port.
static void ready_input(ErlDrvData e, ErlDrvEvent ready_fd)
{
...
res = read(ready_fd, read_buf, ERTS_SYS_READ_BUF_SZ);
if (res < 0) {
if ((errno != EINTR) && (errno != ERRNO_BLOCK))
port_inp_failure(port_num, ready_fd, res);
}
else if (res == 0)
port_inp_failure(port_num, ready_fd, res);
else
driver_output(port_num, (char*) read_buf, res);
erts_free(ERTS_ALC_T_SYS_READ_BUF, (void *) read_buf);
}....
}
static int port_inp_failure(int port_num, int ready_fd, int res)
/* Result: 0 (eof) or -1 (error) */
{
int err = errno;
ASSERT(res <= 0);
(void) driver_select(port_num, ready_fd, ERL_DRV_READ|ERL_DRV_WRITE, 0);
clear_fd_data(ready_fd);
if (res == 0) {
if (driver_data[ready_fd].report_exit) {
CHLD_STAT_LOCK;
if (driver_data[ready_fd].alive) {
/*
* We have eof and want to report exit status, but the process
* hasn't exited yet. When it does report_exit_status() will
* driver_select() this fd which will make sure that we get
* back here with driver_data[ready_fd].alive == 0 and
* driver_data[ready_fd].status set.
*/
CHLD_STAT_UNLOCK;
return 0;
}
else {
int status = driver_data[ready_fd].status;
CHLD_STAT_UNLOCK;
/* We need not be prepared for stopped/continued processes. */
if (WIFSIGNALED(status))
status = 128 + WTERMSIG(status);
else
status = WEXITSTATUS(status);
driver_report_exit(driver_data[ready_fd].port_num, status); }
}
driver_failure_eof(port_num);
} else {
driver_failure_posix(port_num, err);
}
return 0;
}
void driver_report_exit(int ix, int status)
{
Port* prt = erts_drvport2port(ix);
Eterm* hp;
Eterm tuple;
Process *rp;
Eterm pid;
ErlHeapFragment *bp = NULL;
ErlOffHeap *ohp;
ErtsProcLocks rp_locks = 0;
ERTS_SMP_CHK_NO_PROC_LOCKS;
ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt));
pid = prt->connected;
ASSERT(is_internal_pid(pid));
rp = erts_pid2proc_opt(NULL, 0, pid, 0, ERTS_P2P_FLG_SMP_INC_REFC);
if (!rp)
return;
hp = erts_alloc_message_heap(3+3, &bp, &ohp, rp, &rp_locks);
tuple = TUPLE2(hp, am_exit_status, make_small(status));
hp += 3;
tuple = TUPLE2(hp, prt->id, tuple); erts_queue_message(rp, &rp_locks, bp, tuple, am_undefined);
erts_smp_proc_unlock(rp, rp_locks);
erts_smp_proc_dec_refc(rp);
}
于是我们收到{Port, {exit_staus, Staus}}事件。
有点复杂吧,不过挺优雅的。记住信号处理函数里面不能做太耗时和调用有害的api。还有会有大量的退出事件发生,让调度器来调度这个事情比较公平,避免系统在处理退出处理上投入!
发表评论
-
OTP R14A今天发布了
2010-06-17 14:36 2677以下是这次发布的亮点,没有太大的性能改进, 主要是修理了很多B ... -
R14A实现了EEP31,添加了binary模块
2010-05-21 15:15 3030Erlang的binary数据结构非常强大,而且偏向底层,在作 ... -
如何查看节点的可用句柄数目和已用句柄数
2010-04-08 03:31 4814很多同学在使用erlang的过程中, 碰到了很奇怪的问题, 后 ... -
获取Erlang系统信息的代码片段
2010-04-06 21:49 3475从lib/megaco/src/tcp/megaco_tcp_ ... -
iolist跟list有什么区别?
2010-04-06 20:30 6529看到erlang-china.org上有个 ... -
erlang:send_after和erlang:start_timer的使用解释
2010-04-06 18:31 8386前段时间arksea 同学提出这个问题, 因为文档里面写的很不 ... -
Latest news from the Erlang/OTP team at Ericsson 2010
2010-04-05 19:23 2013参考Talk http://www.erlang-factor ... -
对try 异常 运行的疑问,为什么出现两种结果
2010-04-05 19:22 2842郎咸武<langxianzhe@163.com> ... -
Erlang ERTS Async基础设施
2010-03-19 00:03 2517其实Erts的Async做的很不错的, 相当的完备, 性能又高 ... -
CloudI 0.0.9 Released, A Cloud as an Interface
2010-03-09 22:32 2476基于Erlang的云平台 看了下代码 质量还是不错的 完成了不 ... -
Memory matters - even in Erlang (再次说明了了解内存如何工作的必要性)
2010-03-09 20:26 3439原文地址:http://www.lshift.net/blog ... -
Some simple examples of using Erlang’s XPath implementation
2010-03-08 23:30 2050原文地址 http://www.lshift.net/blog ... -
lcnt 环境搭建
2010-02-26 16:19 2614抄书:otp_doc_html_R13B04/lib/tool ... -
Erlang强大的代码重构工具 tidier
2010-02-25 16:22 2486Jan 29, 2010 We are very happy ... -
[Feb 24 2010] Erlang/OTP R13B04 has been released
2010-02-25 00:31 1387Erlang/OTP R13B04 has been rele ... -
R13B04 Installation
2010-01-28 10:28 1390R13B04后erlang的源码编译为了考虑移植性,就改变了编 ... -
Running tests
2010-01-19 14:51 1486R13B03以后 OTP的模块加入了大量的测试模块,这些模块都 ... -
R13B04在细化Binary heap
2010-01-14 15:11 1508从github otp的更新日志可以清楚的看到otp R13B ... -
R13B03 binary vheap有助减少binary内存压力
2009-11-29 16:07 1668R13B03 binary vheap有助减少binary内存 ... -
erl_nif 扩展erlang的另外一种方法
2009-11-26 01:02 3218我们知道扩展erl有2种方法, driver和port. 这2 ...
相关推荐
在 Erlang 中,Port Driver 是一种机制,允许 Erlang 进程与外部 C 库或者其他语言编写的程序进行通信。Port Driver 提供了一种方式,使得 Erlang 系统能够与外部世界交互,执行低级别的I/O操作或调用非Erlang代码...
Erlang作为一种专为构建可扩展、并发和分布式系统而设计的编程语言,其在进程间通信(IPC)领域的应用尤为广泛。Erlang脚本,即以.erl为扩展名的文件,允许用户编写和执行一系列Erlang命令,以实现进程间的通信和...
在Erlang中,进程是并发执行的基本单元,它们轻量级且独立,彼此通过消息传递进行通信。下面将详细介绍Erlang中的进程以及如何使用它们进行并发开发。 1. 进程概念 在Erlang中,进程不同于操作系统中的线程或进程。...
Erlang进程模型特点 一个进程可以创建数以万计的轻量级进程 每个轻量级进程仅仅完成单一功能 一个复杂的功能可以由多个轻量级进程协同完成 当遇到file或socket等阻塞的io时, 调用的轻量级进程被阻塞,整个进程不...
这种机制允许进程捕获并处理伙伴进程的退出情况,增强了系统的容错性。 在"bank2"这个练习中,我们可能会遇到一个简单的银行账户模拟应用,其中包含多个进程来处理不同的账户操作,如存款、取款等。假设我们有以下...
gproc, Erlang的扩展进程注册表 gproc应用程序作者: 超级用户,约瑟夫 Wayne 。扩展进程字典 注释Gproc有两个依赖项:gen_leader 和 edown 。 由于大多数人都不积极使用,所以默认情况下它们不再被获取。要启用 gen...
Erlang中的链接(Linking)和监控(Monitoring)机制允许进程间建立关系,以便在另一进程崩溃时得到通知。链接用于追踪相关进程的状态,而监控则可以观察进程的生存状态。 ### 5. 消息传递 Erlang的进程间通信主要...
在Erlang中,`timer`模块是用于处理定时任务的关键组件,它提供了多种功能,使得开发者能够轻松地创建延时操作或者周期性任务。 `timer`模块的核心功能包括: 1. `tc()`函数:这个函数用于执行一个函数并计算其执行...
这个简单的例子展示了Erlang中基本的进程通信模式,即客户端通过发送请求到服务器,服务器处理请求后返回响应,客户端接收到响应后进行处理。这种模式在并发编程中非常常见,因为Erlang的进程模型非常适合构建分布式...
另一种是通过进程间通信(IPC)的方式让Erlang与C语言程序进行交互。Erlang倾向于采用第二种方式,即进程间通信,来与C语言程序进行交互。 #### 三、Erlang与C语言接口的工作原理 在Erlang中,与C语言程序进行通信...
2. **并发与并行**:Erlang的轻量级进程(称为Erlang进程)使得并发编程变得简单。每个进程有自己的堆栈和消息队列,通过消息传递进行通信,降低了资源消耗,增强了系统的健壮性。 3. **热代码更新**:Erlang支持...
Erlang的性能定量分析涉及对VM行为的深入研究,包括内存使用、进程调度以及垃圾回收(GC)等方面的性能指标。这涉及到监控ERTS的运行时参数,例如ETS(Erlang Term Storage)使用的内存、进程的数量和状态,以及SMP...
Erlang语言的核心特点包括轻量级进程(Erlang中的进程与操作系统进程不同,它们更轻便且能快速切换)、模式匹配、函数式编程和热代码替换等。这些特性使得Erlang在处理高并发场景下表现出色,例如在电信、网络设备和...
- **并发性**:Erlang的进程模型是轻量级的,创建和销毁进程的成本很低,使得处理大量并发连接成为可能。 - **分布式**:Erlang节点可以在多台机器上运行,并可以相互通信,实现分布式计算。 - **热升级**:Erlang...
1. **轻量级进程**:Erlang中的进程非常高效,消耗资源少,可以创建数百万个进程进行并发处理。 2. **分布式**:Erlang节点可以在多台机器上运行,通过简单的节点连接实现分布式计算。 3. **错误恢复**:Erlang提供...
消息分为普通消息和退出信号(exitsignals),处理消息时,程序可以挂起接收进程,或者通过链接(link)和监视监视(monitor)机制来处理进程间的消息传递和监控。此外,Erlang语言推崇函数式编程范式,其中纯函数(pure...
5. **并发与分布式特性**:Erlang以其强大的并发处理能力著称,新版本可能在进程管理、消息传递等方面有进一步的改进。 6. **编译器升级**:Erlang的BEAM虚拟机和编译器可能会有优化,使得编译速度更快,生成的代码...
**并发性**:Erlang的并发模型基于轻量级进程(Lightweight Processes, LWP),这些进程消耗资源极少,使得系统能够同时处理成千上万个并发任务。由于进程间通信主要通过消息传递,而不是共享内存,因此避免了常见的...
此外,还可以对进程进行监控,监控进程的存活状态。 **Erlang的错误处理** 1. **异常处理**:Erlang使用`try...catch...end`结构处理异常,捕获错误并进行相应处理。 2. **错误日志**:Erlang系统提供了标准的日志...
- **轻量级进程**: Erlang VM中的进程非常轻量,每个进程的开销很小,使得系统能够同时处理成千上万个进程。 - **故障隔离**: Erlang VM设计时考虑到了系统的容错性,通过监控和链接机制实现了故障隔离。 - **...