IPC : pipe, named pipe, semaphore, message queue, shared memory, futex, socket
Futex : fast userspace mutex(Spinlock 방식)
- 장점 : 빠름 (sleep 대신 while),
lock이 user space에 있기 때문에 접근성이 좋음(공유 메모리나 Thread 및 Process간 공유 가능)
- 단점 : 기본적으로 loop를 계속 돌고 있기 때문에 core수가 뒷받침되어야 한다.
(single core에서는 소용 없음.)
pthread mutex vs pthread spinlock
Pasted from <http://www.alexonlinux.com/pthread-mutex-vs-pthread-spinlock>
Pselect()
int pselect(int nfds, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, const struct timespec *timeout,
const sigset_t *sigmask);
• pselect는 struct timespec 구조체 사용한다. timespec 구조체를 사용함으로써 나노초까지 세밀하게 조정할 수 있게 되었다.
struct timespec {
long tv_sec; /* seconds */
long tv_nsec; /* nanoseconds */
};
• pselect 는 Linux(:12) 커널 2.6.16에 추가되었다. 이전에는 glibc에서 애뮬레이트한 함수가 제공되었으나 버그를 가지고 있었다.
• sigmask를 사용해서 시그널을 블럭시킬 수 있다. select의 경우 수행되는 도중에 시그널에 의한 인터럽트가 발생하게 되면, race condition 혹은 무한 블록킹 상태에 놓일 수 있었다. pselect를 사용하면 이러한 문제를 제거할 수 있다.
Pasted from <http://www.joinc.co.kr/modules/moniwiki/wiki.php/man/2/select>
Pselect가 select와 다른 점
- Nano sec단위로 사용하므로 이론적으로는 타이머 해상도가 정밀하나 실전에서는 micro sec단위도 안정적으로 제공하지 못한다.
- Timeout parameter를 변경하지 않는다. 사용할 때마다 timeout을 다시 설정할 필요가 없음
- Signal parameter가 추가됨(sigmask) : signal 을 차단함.
Select() : 동기식 다중 입출력 제공
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
Int select (int n,
fd_set *readfds,
fd_set *writefds,
fd_set *execptfds,
struct timeval *timeout);
FD_CLR(int fd, fd_set *set); /* delete FD */
FD_ISSET(int fd, fd_set *set); /* select의 결과에 해당 fd가 있는지 */
FD_SET(int fd, fd_set *set); /* add FD*/
FD_ZERO(fd_set *set);
#include <sys/time.h>
Struct timeval {
long tv_sec; /* sec */
long tv_usec; /* micro sec */
};
Poll() : select를 보완 (fd set을 하나로 통일)
#include <sys/poll.h>
Int poll (struct pollfd *fds, unsigned int nfds, int timeout);
#include <sys/poll.h>
Struct pollfd {
int fd;
short events; /* 감시 대상 요청 */
short revents; /* returned event */
}
Events:
POLLIN : Data other than high-priority data may be read without blocking.
POLLRDNORM : Normal data may be read without blocking.
POLLRDBAND : Priority data may be read without blocking.
POLLPRI : High-priority data may be read without blocking.
POLLOUT : Normal data may be written without blocking.
POLLWRNORM : Equivalent to POLLOUT.
POLLWRBAND : Priority data may be written.
POLLERR : An error has occurred on the device or stream. This flag is only valid in the revents bitmask; it shall be ignored in the events member.
POLLHUP : The device has been disconnected. This event and POLLOUT are mutually-exclusive; a stream can never be writable if a hangup has occurred. However, this event and POLLIN, POLLRDNORM, POLLRDBAND, or POLLPRI are not mutually-exclusive. This flag is only valid in the revents bitmask; it shall be ignored in the events member.
POLLNVAL : The specified fd value is invalid. This flag is only valid in the revents member; it shall ignored in the events member.
Ppoll() : pselect 처럼 만든 것, 나노초 단위, sigmask 제공, linux 전용
#define _GNU_SOURCE
#include <sys/poll.h>
Int ppoll (struct pollfd *fds,
nfds_t nfds,
const struct timespec *timeout,
const sigset_t *sigmask);
Poll과 select 비교
oll
select
매개변수에
+1(fd+1)이 필요없다
fd의
숫자가 큰 경우 select보다 효율적
fd_set값이
크면 비효율적이다. bitmask를 모두 검사하며 특히 bit가 분산된 경우 더욱 비효율적이다
매번
set을 초기화해야 한다.(FD_ZERO)
이식성을
높이기 위해 timeout parameter(timeval)를 매번 초기화 해야함
Pselect() 를 사용할 경우 초기화 안해도 됨
몇몇
UNIX에서는 poll을 지원하지 않는다
이식성이
높다
microsecond단위까지는
timeout resolution이 더 좋다
Pasted
from <http://bluelimn.tistory.com/entry/2-epoll-select-poll >
Select example(server) 접기
server.c
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define TIMEOUT 10 /* timeout : seconds */
#define FD_MAX_CLIENT 3
#define BUF_SIZE 1024
#define EXIT_STR "exit"
/*
* error - wrapper for perror
*/
void error(char *msg) {
perror(msg);
exit(1);
}
int main(int argc, char **argv)
{
int server_sockfd;
int client_sockfd;
int max_fd; /* for using select */
struct sockaddr_in serveraddr;
struct sockaddr_in clientaddr;
int clientlen;
int client[FD_MAX_CLIENT];
char buf[BUF_SIZE]; /* message buffer */
int n; /* message byte size */
struct timeval tv;
fd_set readfds, temp_fds;
int notdone;
int i, ret;
/* socket: create the parent socket */
server_sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (server_sockfd < 0)
error("ERROR opening socket");
max_fd = server_sockfd;
bzero((char*)&serveraddr, sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
serveraddr.sin_port = htons(9000);
if(bind(server_sockfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) < 0)
error("ERROR on binding");
if(listen(server_sockfd, 5) < 0) /* allow 5 requests(backlog) to queue up */
error("ERROR on listen");
for (i = 0; i < FD_MAX_CLIENT; i++) {
client[i] = -1;
}
/* initialize some things for the main loop */
clientlen = sizeof(clientaddr);
notdone = 1;
printf("TCP Server Waiting ...\n");
fflush(stdout);
FD_ZERO(&readfds); /* initialize the fd set */
FD_SET(server_sockfd, &readfds); /* add socket fd */
while(notdone)
{
temp_fds = readfds;
tv.tv_sec = TIMEOUT;
tv.tv_usec = 0;
ret = select(max_fd+1, &temp_fds, 0, 0, &tv);
if (ret < 0)
error("ERROR in select");
else if(ret == 0)
{
printf("waiting...\n");
continue;
}
if (FD_ISSET(server_sockfd, &temp_fds)) {
/* accept: wait for a connection request */
client_sockfd = accept(server_sockfd, (struct sockaddr *)&clientaddr, &clientlen);
if(client_sockfd < 0)
error("ERROR on accept");
printf("connection from (%s , %d)\n", inet_ntoa(clientaddr.sin_addr),ntohs(clientaddr.sin_port));
for (i = 0; i < FD_MAX_CLIENT; i++)
{
if (client[i] < 0) {
client[i] = client_sockfd;
printf("\nclient_idx=%d, client_sockfd=%d\n", i, client_sockfd);
break;
}
}
if(i >= FD_MAX_CLIENT)
{
printf("too many clients. so, closing client fd[%d]\n", client_sockfd);
close(client_sockfd);
continue;
}
FD_SET(client_sockfd, &readfds); /* add socket fd */
max_fd = (client_sockfd > max_fd)?(client_sockfd):(max_fd);
}
for (i = 0; i <= FD_MAX_CLIENT; i++)
{
if (client[i] < 0)
continue;
client_sockfd = client[i];
if (FD_ISSET(client_sockfd, &temp_fds))
{
bzero(buf, BUF_SIZE);
/* n = recv(client_sockfd, buf, BUF_SIZE, 0); */
n = read(client_sockfd, buf, BUF_SIZE);
if (n <= 0) {
printf("Close client_sockfd : %d", client_sockfd);
close(client_sockfd);
FD_CLR(client_sockfd, &readfds);
client[i] = -1;
}
printf("[%d]RECV %s\n", client_sockfd, buf);
if(strncmp(buf,EXIT_STR,strlen(EXIT_STR)) == 0)
{
notdone = 0;
break;
}
/* send(client_sockfd,buf,strlen(buf), 0); */
write(client_sockfd, buf, strlen(buf));
break;
}
}
}
/* clean up */
printf("\nTerminating server.\n");
close(server_sockfd);
exit(0);
}
접기
Select example(client) 접기
client.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <errno.h>
#include <netdb.h>
#define BUF_SIZE 1024
#define EXIT_STR "exit"
/*
* error - wrapper for perror
*/
void error(char *msg) {
perror(msg);
exit(0);
}
int main()
{
int sockfd, n;
char send_data[BUF_SIZE],recv_data[BUF_SIZE];
struct hostent *host;
struct sockaddr_in server_addr;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
host = gethostbyname("127.0.0.1");
if (host == NULL)
error("ERROR, no such host");
bzero((char*) &server_addr, sizeof(server_addr));
server_addr.sin_addr = *((struct in_addr *)host->h_addr);
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(9000);
/* connect: create a connection with the server */
if (connect(sockfd, (struct sockaddr *) &server_addr, sizeof(struct sockaddr)) < 0)
error("ERROR connecting");
while(1) {
printf("Please enter msg: ");
bzero(send_data, BUF_SIZE);
fgets(send_data, sizeof(send_data), stdin);
/*n = send(sockfd,send_data,strlen(send_data), 0);*/
n = write(sockfd,send_data,strlen(send_data));
if (n < 0)
error("ERROR writing to socket");
if(strncmp(send_data , EXIT_STR, strlen(EXIT_STR)) == 0)
{
close(sockfd);
break;
}
bzero(recv_data, BUF_SIZE);
n = read(sockfd, recv_data, BUF_SIZE);
/*n = recv(sockfd, recv_data, BUF_SIZE,0);*/
if (n < 0)
error("ERROR reading from socket");
printf("RECV = %s\n" , recv_data);
}
return 0;
}
접기
Poll example 접기
poll.c
#include <stdio.h>
#include <unistd.h>
#include <sys/poll.h>
#define TIMEOUT 5000 /* msec */
int main(void)
{
struct pollfd fds[2];
int ret;
/* waiting at stdin */
fds[0].fd = STDIN_FILENO;
fds[0].events = POLLIN;
/* check to can write to stdout */
fds[1].fd = STDOUT_FILENO;
fds[1].events = POLLOUT;
ret = poll(fds, 2, TIMEOUT);
if(ret == -1)
{
perror("poll");
return 1;
}
if(!ret)
{
printf("timeout : %d(ms)\n", TIMEOUT);
return 0;
}
if(fds[0].revents & POLLIN)
printf("stdin is readable\n");
if(fds[1].revents & POLLOUT)
printf("stdout is writable\n");
return 0;
}
==========================================
$ ./poll
Stdout is wriable
$ ./poll < test.txt
Stdin is readable
Stdout is writable
접기