Thursday, March 3, 2011

NetApp的Phone Interview惨败(一)

1. What is the difference between a mutex and a spinlock?

当头第一棒,一下子就把我捶晕了。mutex我当然明白了,就是个binary semaphore。但是spinlock我从没接触过。

在网上搜索一番,总算找到了答案:
http://www.alexonlinux.com/pthread-spinlocks
http://www.alexonlinux.com/pthread-mutex-vs-pthread-spinlock

According to the author, spinlock is more effective (than mutex) in term of CPU consumption and speed.

Things to note:

(1) Spinlocks perform better than mutexes in this particular setup, on multi-processor computer.
(2) Spinlocks are totally useless on uni-processor computers. This is due to a nature of spinlocks.


2. GDB调试程序的时候,attach之后,怎样显示thread information?

这个我也傻眼了。以前用GDB的时候最多就是用backtrace(bt)命令检查一下coredump里面的信息,还真没用过attach,更不要说显示线程信息了。

还是Google帮忙:
http://sourceware.org/gdb/onlinedocs/gdb/Threads.html
http://developer.apple.com/library/mac/#documentation/DeveloperTools/gdb/gdb/gdb_5.html
http://stackoverflow.com/questions/47701/is-there-a-way-to-attach-a-debugger-to-a-multi-threaded-python-process

The most basic command is "info threads".


3. In network socket programming, what are the basic APIs?

我提到先用socket()做initialization,再分配address,whether it is IPv4 or IPv6。接着在server端是listen() and accept(),在client端,开始也是initialization,接着应该是某个send request的function,但是具体我记不清了,以前在Richard Stevens的Unix Network Programming, 2nd Edition, Volume 1里面见过。

Interviewer后来说client端send出request的function是connect(),server端还缺少一个bind()。

考这个题我稍微有点意见,何必问这种书上一查就有的东西呢?当然,如果说从这个问题察看我网络编程的熟练程度,我也无话可说。

还是查一下Stevens的书吧,先看server的例子:

1 #include "unp.h"

2 int
3 main(int argc, char **argv)
4 {
5     int listenfd, connfd;
6     pid_t childpid;
7     socklen_t clilen;
8     struct sockaddr_in cliaddr, servaddr;

9     listenfd = Socket (AF_INET, SOCK_STREAM, 0);

10   bzero(&servaddr, sizeof(servaddr));
11   servaddr.sin_family = AF_INET;
12   servaddr.sin_addr.s_addr = htonl (INADDR_ANY);
13   servaddr.sin_port = htons (SERV_PORT);

14   Bind(listenfd, (SA *) &servaddr, sizeof(servaddr));

15   Listen(listenfd, LISTENQ);

16   for ( ; ; ) {
17       clilen = sizeof(cliaddr);
18       connfd = Accept(listenfd, (SA *) &cliaddr, &clilen);

19       if ( (childpid = Fork()) == 0) { /* child process */
20           Close(listenfd); /* close listening socket */
21           str_echo(connfd); /* process the request */
22           exit (0);
23       }
24       Close(connfd); /* parent closes connected socket */
25   }
26 }

1 #include "unp.h"

2 void
3 str_echo(int sockfd)
4 {
5     ssize_t n;
6     char buf[MAXLINE];

7   again:
8     while ( (n = read(sockfd, buf, MAXLINE)) > 0)
9         Writen(sockfd, buf, n);

10   if (n < 0 && errno == EINTR)
11       goto again;
12   else if (n < 0)
13       err_sys("str_echo: read error");
14 }

摘自Section 5.2 and 5.3,code都是self explanatory的,不用多说什么。

再来看看client端的code:

1 #include "unp.h"

2 int
3 main(int argc, char **argv)
4 {
5     int sockfd;
6     struct sockaddr_in servaddr;

7     if (argc != 2)
8         err_quit("usage: tcpcli ");

9     sockfd = Socket(AF_INET, SOCK_STREAM, 0);

10   bzero(&servaddr, sizeof(servaddr));
11   servaddr.sin_family = AF_INET;
12   servaddr.sin_port = htons(SERV_PORT);
13   Inet_pton(AF_INET, argv[1], &servaddr.sin_addr);

14   Connect(sockfd, (SA *) &servaddr, sizeof(servaddr));

15   str_cli(stdin, sockfd); /* do it all */

16   exit(0);
17 }

1 #include "unp.h"

2 void
3 str_cli(FILE *fp, int sockfd)
4 {
5     char sendline[MAXLINE], recvline[MAXLINE];

6     while (Fgets(sendline, MAXLINE, fp) != NULL) {
7         Writen(sockfd, sendline, strlen (sendline));

8         if (Readline(sockfd, recvline, MAXLINE) == 0)
9             err_quit("str_cli: server terminated prematurely");

10       Fputs(recvline, stdout);
11   }
12 }

摘自Section 5.4 and 5.5,也不用多作解释。没啥办法,手不熟,难怪会被问倒。

Wikipedia上面有个简洁的介绍:http://en.wikipedia.org/wiki/Berkeley_sockets,可供快速参考。

后来interviewer又问我,如果server有两个port可以accept connection from client,应该用怎样的function?我提到select(),他认可了,没有追究怎样实现的细节。问了我也不会。

这篇文章(http://stackoverflow.com/questions/3655053/python-listen-on-two-ports)谈到一些,不过细节还不是很深入。UNP第1卷第6章I/O Multiplexing也可以参考。

Basically, the idea is to create two sockets with each port, and listen on these two sockets. Then select() will let you know which socket is ready and when, so you can accept() appropriately.

这个Unix Socket FAQ论坛(http://developerweb.net/viewtopic.php?pid=23096)里面的mlampkin也简明扼要地列出了以下的要点:

The select function is designed to handle multiple sockets so the only changes you would need to make are:

* Create 3 more server sockets ( bound / listening ) with the new addresses - port pairs.
* Change the select nfds parameter from 1 to 4, add the new server sockets to the readfds group and potentially the errorfds group.
* When you call select and it returns, just iterate thru the readfds group with FD_ISSET to determine which socket actually is accepting a new connection.

While you could add a lot more complexity, in simplest terms that really should be about it...

by Michael

1 comment:

  1. you have very good attitude for the interview I should learn from you

    ReplyDelete