2011年12月27日 星期二

[C++] template class instantiation

驗證一下, 在template class當中, 如果有method不依靠template class type T, 這樣還是會產生出兩份不一樣的code, 因為template本身在instantiation的時候就會被當作兩個不同的class.


#include <iostream>
template
class Foo
{
public:
T goo(T a) { return a + a; };
int foo(int a) { return a;};
};

int main()
{
Foo a;
Foo b;

a.goo(12);
b.goo(1.2);
a.foo(1);
b.foo(1);
return 0;
}

可以看到main裡面, _ZN3FooIiE3fooEi, _ZN3FooIdE3fooEi 是被call到兩個不同的function, 就算裡面code是完全一樣的


.file "template_gen.cpp"
.local _ZStL8__ioinit
.comm _ZStL8__ioinit,1,1
.text
.globl main
.type main, @function
main:
.LFB959:
.cfi_startproc
.cfi_personality 0x3,__gxx_personality_v0
pushq %rbp
.cfi_def_cfa_offset 16
movq %rsp, %rbp
.cfi_offset 6, -16
.cfi_def_cfa_register 6
subq $16, %rsp
leaq -1(%rbp), %rax
movl $12, %esi
movq %rax, %rdi
call _ZN3FooIiE3gooEi
movsd .LC0(%rip), %xmm0
leaq -2(%rbp), %rax
movq %rax, %rdi
call _ZN3FooIdE3gooEd
leaq -1(%rbp), %rax
movl $1, %esi
movq %rax, %rdi
call _ZN3FooIiE3fooEi
leaq -2(%rbp), %rax
movl $1, %esi
movq %rax, %rdi
call _ZN3FooIdE3fooEi
movl $0, %eax
leave
ret
.cfi_endproc

...略

_ZN3FooIiE3fooEi:
.LFB962:
.cfi_startproc
.cfi_personality 0x3,__gxx_personality_v0
pushq %rbp
.cfi_def_cfa_offset 16
movq %rsp, %rbp
.cfi_offset 6, -16
.cfi_def_cfa_register 6
movq %rdi, -8(%rbp)
movl %esi, -12(%rbp)
movl -12(%rbp), %eax
leave
ret
.cfi_endproc
.LFE962:
.size _ZN3FooIiE3fooEi, .-_ZN3FooIiE3fooEi
.section .text._ZN3FooIdE3fooEi,"axG",@progbits,_ZN3FooIdE3fooEi,comdat
.align 2
.weak _ZN3FooIdE3fooEi
.type _ZN3FooIdE3fooEi, @function
_ZN3FooIdE3fooEi:
.LFB963:
.cfi_startproc
.cfi_personality 0x3,__gxx_personality_v0
pushq %rbp
.cfi_def_cfa_offset 16
movq %rsp, %rbp
.cfi_offset 6, -16
.cfi_def_cfa_register 6
movq %rdi, -8(%rbp)
movl %esi, -12(%rbp)
movl -12(%rbp), %eax
leave
ret
.cfi_endproc

...略

2011年12月15日 星期四

[Linux] process use multi-core CPU



/*
* The following code use sched_setaffinity to set CPU mask
* it will fork process and each process will run on only one core
*
* you can read from /proc/cpuinfo to get the number of processor
*/
int setup_multicore(int n)
{
cpu_set_t *cpuset = CPU_ALLOC(n);
size_t size = CPU_ALLOC_SIZE(n);
CPU_ZERO_S(size, cpuset);
CPU_SET_S(0, size, cpuset);
if (sched_setaffinity(getpid(), size, cpuset) < 0) {
CPU_FREE(cpuset);
return -1;
}
pid_t pid = 0;
// fork a child for each core
for (int i = 1; i < n; ++i) {
pid = fork();
if (pid 0)
continue;
CPU_ZERO_S(size, cpuset);
CPU_SET_S(i, size, cpuset);
if (sched_setaffinity(getpid(), size, cpuset) < 0) {
CPU_FREE(cpuset);
return -1;
}
break;
}
CPU_FREE(cpuset);
}

2011年12月7日 星期三

[Linux] Signal should not be block

The following signal should be deliverd on the thread that generated the original error. Blocking them interferes with proper recovery


sigdelset(sig_mask, SIGABRT);
sigdelset(sig_mask, SIGBUS);
sigdelset(sig_mask, SIGEMT);
sigdelset(sig_mask, SIGFPE);
sigdelset(sig_mask, SIGILL);
sigdelset(sig_mask, SIGIOT);
sigdelset(sig_mask, SIGPIPE);
sigdelset(sig_mask, SIGSEGV);
sigdelset(sig_mask, SIGSYS);
sigdelset(sig_mask, SIGTRAP);

待續...

2011年12月1日 星期四

[Pthread] signal handler on other thread

在multithread程式裡面, 不管你是由child thread還是main thread 註冊signal handler, 在signal handler都是在main thread處理.
可以從下面的範例看出


#include
#include
#include
#include

static void hdl (int sig, siginfo_t *siginfo, void *context)
{
pthread_t ret = pthread_self();
sleep(2);
printf ("Sending PID: %ld, UID: %ld, self=%u\n",
(long)siginfo->si_pid, (long)siginfo->si_uid, pthread_self());
}

void *child1_fun(void *data)
{
struct sigaction act;

memset (&act, '\0', sizeof(act));
printf("child1 pid=%u\n", pthread_self());
/* Use the sa_sigaction field because the handles has two additional parameters */
act.sa_sigaction = &hdl;
/* The SA_SIGINFO flag tells sigaction() to use the sa_sigaction field, not sa_handler. */
act.sa_flags = SA_SIGINFO;
if (sigaction(SIGALRM, &act, NULL) < 0) {
perror ("sigaction");
return 1;
}
pause();
}

void *child2_fun(void *data)
{
pthread_t *child1 = (pthread_t *) data;
printf("child2 pid=%u\n", pthread_self());
//alarm(2);
struct itimerval timer;

timer.it_value.tv_sec = 5 ;
timer.it_value.tv_usec = 0;
timer.it_interval.tv_sec = 5;
timer.it_interval.tv_usec = 0;
setitimer(ITIMER_REAL, &timer, NULL);
// pthread_kill(*child1, SIGALRM);
}
int main (int argc, char *argv[])
{
pthread_t child1, child2;
sigset_t newSet;
sigset_t oset;
sigemptyset(&newSet);
sigaddset(&newSet, SIGALRM);
pthread_sigmask(SIG_BLOCK, &newSet, NULL);

printf("main pid=%u\n", pthread_self());
pthread_create(&child1, NULL, child1_fun, NULL);
pthread_create(&child2, NULL, child2_fun, &child1);
pthread_join(child1, NULL);

return 0;
}

可以看到都是main thread在處理signal.
Output:


ytshen@ytshen-ThinkCentre-A58:~/temp$ ./a.out
main pid=256317184
child1 pid=248338176
child2 pid=239945472
Sending PID: 0, UID: 0, self=256317184
Sending PID: 0, UID: 0, self=256317184
^C
ytshen@ytshen-ThinkCentre-A58:~/temp$

當我們希望是尤其他的child thread來處理signal, 我們就必須要改成這樣, 要先在main thread用sigmask 把不想接得signal設成SIG_BLOCK (非常重要! 不然當signal發生他會當你沒有註冊任何signal handler, 造成program stop), 在child thread 呼叫sigwait的時候, 他就會wait你想要wait的signal


#include
#include
#include
#include
#include
#include

void *child1_fun(void *data)
{
sigset_t newSet;
sigemptyset(&newSet);
sigaddset(&newSet, SIGALRM);
int signum;
while(1) {
printf("child1 pid=%u start to wait\n", pthread_self());
sigwait(&newSet, &signum);
printf("child1 pid=%u get signal = %d!\n", pthread_self(), signum);
}
}

void *child2_fun(void *data)
{
pthread_t *child1 = (pthread_t *) data;
printf("child2 pid=%u\n", pthread_self());
//alarm(2);
struct itimerval timer;

timer.it_value.tv_sec = 5 ;
timer.it_value.tv_usec = 0;
timer.it_interval.tv_sec = 5;
timer.it_interval.tv_usec = 0;
setitimer(ITIMER_REAL, &timer, NULL);
// pthread_kill(*child1, SIGALRM);
}

int main (int argc, char *argv[])
{
pthread_t child1, child2;
sigset_t newSet;
sigset_t oset;
sigemptyset(&newSet);
sigaddset(&newSet, SIGALRM);
pthread_sigmask(SIG_BLOCK, &newSet, NULL);

printf("main pid=%u\n", pthread_self());
pthread_create(&child1, NULL, child1_fun, NULL);
pthread_create(&child2, NULL, child2_fun, &child1);
pthread_join(child1, NULL);

}

Output:


ytshen@ytshen-ThinkCentre-A58:~/temp$ ./a.out
main pid=1378113280
child1 pid=1370134272 start to wait
child2 pid=1361741568
child1 pid=1370134272 get signal = 14!
child1 pid=1370134272 start to wait
child1 pid=1370134272 get signal = 14!
child1 pid=1370134272 start to wait
^C
ytshen@ytshen-ThinkCentre-A58:~/temp$

Updated!!
保險作法是在main thread create其他所有thread之前, sigprocmask 把該signal block住, 在create child thread(這樣所有child thread也會繼承main thread signal mask), 然後在要處理signal的child thread去sigwait, 這樣就不會有其他沒有block該signal的child thread因為沒有處理而被terminate!

Reference:
http://www.cognitus.net/html/howto/pthreadSemiFAQ_8.html
http://stackoverflow.com/questions/5282099/signal-handling-in-pthreads
http://blog.csdn.net/wozaiwogu/article/details/4361456
http://blog.csdn.net/fytzzh/article/details/660457