|
Á¦ 3 ȸ ¸®´ª½º °øµ¿Ã¼ ¼¼¹Ì³ª j ¼¼¼Ç |
|
posix ¸ÖƼ ¾²·¹µùÀ» ÀÌ¿ëÇÑ °£´ÜÇÑ Ã¼ÆÃ¼¹ö ¸¸µé±â! |
||
|
||
|
|
|
ÀÌÀÎÈ£ |
||
c¾ð¾î´Â ¾ËÁö¸¸ ³×Æ®¿öÅ© ÇÁ·Î±×·¡¹ÖÀº ÇØº» ÀûÀÌ ¾øÀ¸½Å ºÐ °£´ÜÇÑ Ã¼ÆÃ ¼¹ö¸¦ ¸¸µé¾î º¾´Ï´Ù posix thread¸¦ ÀÌ¿ëÇÑ ¸ÖƼ¾²·¹µù ÇÁ·Î±×·¡¹ÖÀ» ÀÍÈ÷´Âµ¥ ÁßÁ¡À» µÓ´Ï´Ù ±×¸®°í ³×Æ®¿öÅ© ÇÁ·Î±×·¥À» ¸¸µå´Â ¹æ¹ýµµ °£·«È÷ ¼³¸íÇÕ´Ï´Ù |
posix ¸ÖƼ ¾²·¹µùÀ» ÀÌ¿ëÇÑ °£´ÜÇÑ Ã¼ÆÃ¼¹ö ¸¸µé±â! 361
------------------------------------------------------------------------------------------------
tcp ÇÁ·Î±×·¡¹ÖÀÇ ±âº»
ÀÎÅÍ³Ý ÇÁ·Î±×·¡¹Ö¿¡ ¸¹ÀÌ ¾²´Â ¼ÒÄÏ ÇÁ·Î±×·¡¹Ö¿¡ ´ëÇØ ¾Ë¾Æº¸°Ú½À´Ï´Ù. Åë½Å ¹æ¹ý¿¡´Â '¿¬°á ÁöÇâÇü' °ú 'ºñ¿¬°á ÁöÇâÇü' ÀÌ ÀÖ½À´Ï´Ù. '¿¬°á ÁöÇâÇü(connection-oriented)' °ú 'ºñ¿¬°á ÁöÇâÇü(connectionless)'ÀÇ Â÷ÀÌÁ¡Àº ÀÎÁõ(accept) °úÁ¤À» °ÅÄ¡´À³Ä ¾Æ´Ï³Ä ÇÏ´Â Â÷ÀÌÀÔ´Ï´Ù. '¿¬°á ÁöÇâÇü'Àº '1:1 Åë½Å' °ú ºñ½ÁÇÑ ¹æ¹ýÀ̶ó°í »ý°¢ÇÏ½Ã¸é µË´Ï´Ù. 'ºñ¿¬°á ÁöÇâÇü'Àº ÀÎÁõ°úÁ¤À» °ÅÄ¡Áö ¾Ê½À´Ï´Ù. µû¶ó¼ ÇÑ Æ÷Æ®¿¡ ´Ù¼öÀÇ Å¬¶óÀÌ¾ðÆ®°¡ Á¤º¸¸¦ º¸³¾ ¼ö ÀÖÀ¸³ª Åë½ÅÀÇ Á¤È®¼ºÀÌ ¶³¾îÁö´Â ´ÜÁ¡ÀÌ ÀÖ½À´Ï´Ù. üÆÃ ¼¹ö´Â '¿¬°á ÁöÇâÇü'À» »ç¿ëÇØ¼ ¸¸µé¾î º¸°Ú½À´Ï´Ù.
1) ¼¹ö ÇÁ·Î±×·¡¹Ö
¼¹ö¿¡¼ ¿¬°áÇÏ´Â ÀýÂ÷´Â ´ÙÀ½°ú °°½À´Ï´Ù.
¡¤socket();
¼ÒÄÏ µð½ºÅ©¸³Å͸¦ ÇÒ´çÇØ ÁÝ´Ï´Ù.
¡¤bind();
¼ÒÄÏ µð½ºÅ©¸³Å͸¦ port¿Í ¿¬°áÇØ ÁÝ´Ï´Ù.
¡¤listen();
ÃÖ´ë·Î Çã¿ëÇÏ´Â À¯Àú¼ö¸¦ ¼³Á¤ÇÕ´Ï´Ù.
¡¤accept();
¿¬°áÀ» ½ÂÀÎÇÕ´Ï´Ù. ¶Ç, ¼¹ö´Â read()¸¦ ÀÌ¿ëÇØ¼ µ¥ÀÌÅ͸¦ Àоî¿À°í, write()¸¦ ÀÌ¿ëÇØ¼ µ¥ÀÌÅ͸¦ Àü¼ÛÇÕ´Ï´Ù.
int socket(int domain, int type, int protocol);
domainÀº ÇÁ·ÎÅäÄÝ ÇüŸ¦ Á¤ÇÕ´Ï´Ù. af_unix¿Í af_inetÀÌ Àִµ¥ af_unix´Â °°Àº È£½ºÆ® ³»¿¡¼¸¸ ¾²´Â °ÍÀ̰í, af_inetÀº ´Ù¸¥ È£½ºÆ®¿¡¼µµ ¾µ ¼ö ÀÖ½À´Ï´Ù.
typeÀº ¿¬°áÁöÇâÀÎÁö, ºñ¿¬°á ÁöÇâÀÎÁö¸¦ Á¤ÇÕ´Ï´Ù. ¿¬°áÁöÇâÀº sock_stream, ºñ¿¬°á ÁöÇâÀº sock_dgramÀÔ´Ï´Ù.
protocolÀº ƯÁ¤ ÇÁ·ÎÅäÄÝÀ» ÁöÁ¤ÇÕ´Ï´Ù. º¸ÅëÀº 0ÀÔ´Ï´Ù.(Çϳª ¹Û¿¡ ¾øÀ¸¹Ç·Î...)
int bint(int s, const struct sockaddr *address, size_t address_len);
s¿¡´Â socket¿¡¼ ¸®ÅϵǴ °ªÀ» ³Ö¾îÁÝ´Ï´Ù.
address´Â ...
struct sockaddr_in {
short sin_family;
u_short sin_port;
struct in_addr sin_addr;
char sin_zero[8];
};
sin_family´Â af_inetÀ¸·Î ÇÕ´Ï´Ù. sin_port´Â »ç¿ëÇÒ port¹øÈ£ÀÔ´Ï´Ù. sin_addrÀº ¸ðµç È£½ºÆ®¿¡¼ÀÇ Á¢¼ÓÀ» Çã¿ëÇϱâ À§ÇØ inaddr_any·Î ÇÕ´Ï´Ù.
address_lenÀº *addressÀÇ »çÀÌÁ ÁöÁ¤ÇØ ÁÝ´Ï´Ù.
int listen(int s, int backlog);
backlog´Â ¾ó¸¶³ª ¸¹Àº ¿¬°áÀ» ÇѲ¨¹ø¿¡ Çã¿ëÇÒ °ÍÀÎÁö Á¤ÇÕ´Ï´Ù.
int accept(int s, struct sockaddr *address, int *address_len);
address¿¡´Â clientÀÇ Á¤º¸¸¦ ´ã°í, address_lenÀº ¹öÆÛÀÇ Å©±â(struct sockaddrÀÇ Å©±â)¸¦ ³Ö¾îÁÝ´Ï´Ù.
¿¹Á¦1) client¿Í ¿¬°á ÇÑ ÈÄ À̸§À» ¹°¾îº¸°í ``hello! ''¸¦ Ãâ·ÂÇÏ´Â ÇÁ·Î±×·¥ ¶ó´Â ¸Þ½ÃÁö¸¦ Ãâ·ÂÇϰí Á¾·áÇÏ´Â ÇÁ·Î±×·¥
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
main() {
int sockfd,fd,clilen,nsize;
struct sockaddr_in addr,cliaddr;
char buf[128];
sockfd = socket(af_inet,sock_stream,0);
addr.sin_family=af_inet;
addr.sin_addr.s_addr = htonl(inaddr_any);
addr.sin_port = htons(1000);
bind(sockfd,(struct sockaddr *)&addr,sizeof(addr));
listen(sockfd,5);
clilen = sizeof(cliaddr);
fd = accept(sockfd, (struct sockaddr *) &cliaddr, &clilen);
if(fd<0) {
perror("accept failed");
return 0;
}
nsize = read(fd,buf,sizeof(buf));
write(fd,"hello",5);
write(fd,buf,nsize);
close(fd);
close(sockfd);
}
hton*, ntoh* ÇÔ¼öµé...
hton* ÇÔ¼öµéÀ» »ç¿ëÇÏ´Â ÀÌÀ¯´Â È£½ºÆ® ÄÄÇ»ÅÍ¿Í ³×Æ®¿öÅ© »çÀÌ¿¡ ¹ÙÀÌÆ® ¿À´õ¸µ (byte ordering)ÀÌ ´Ù¸¦ ¼ö Àֱ⠶§¹®ÀÔ´Ï´Ù. ¿¹¸¦µé¾î 0x3130À̶õ ¼ýÀÚ¸¦ ÀúÀåÇÒ ¶§, ¾î¶² ½Ã½ºÅÛÀº 0x3130 À̶ó ÀúÀåÇÏ°í ¾î¶² ½Ã½ºÅÛÀº 0x3031 ·Î µÚÁý¾î¼ ÀúÀåÀ» Çϱ⵵ ÇÕ´Ï´Ù. ³×Æ®¿öÅ© »ó¿¡¼´Â °°Àº ¹ÙÀÌÆ® ¿À´õ¸µÀ» »ç¿ëÇØ¾ß Çϱ⠶§¹®¿¡ hton* ·ùÀÇ ÇÔ¼ö¸¦ »ç¿ëÇÕ´Ï´Ù. hton* Àº È£½ºÆ®ÀÇ ¹ÙÀÌÆ® ¿À´õ¸µÀ» ³×Æ®¿öÅ© ¹ÙÀÌÆ® ¿À´õ¸µÀ¸·Î, ntoh* ´Â ³×Æ®¿öÅ©ÀÇ ¹ÙÀÌÆ® ¿À´õ¸µÀ» È£½ºÆ®ÀÇ ¹ÙÀÌÆ® ¿À´õ¸µÀ¸·Î ¹Ù²ã ÁÝ´Ï´Ù. linux¿¡¼´Â ¾È ½áµµ µÇ´Â µí ÇÕ´Ï´Ù.
2) Ŭ¶óÀÌ¾ðÆ® ÇÁ·Î±×·¡¹Ö
Ŭ¶óÀÌ¾ðÆ® ÇÁ·Î±×·¥ÀÇ ¼ø¼´Â ´ÙÀ½°ú °°½À´Ï´Ù.
¡¤socket();
¼¹ö¿Í °°½À´Ï´Ù.
¡¤connect();
¼¹ö¿Í ¿¬°áÀ» ÇÕ´Ï´Ù.
#include <sys/socket.h>
int connect(int s, struct sockaddr *serv_addr, int addrlen);
s´Â socket();¿¡¼ ¾òÀº ¼ÒÄÏ µð½ºÅ©¸³ÅÍ. serv_addrÀº ¿¬°áÇÒ ¼¹ö¸¦ ÁöÁ¤ÇØ ÁÝ´Ï´Ù.
¿¹Á¦1°ú °°Àº ¼¹ö¸¦ »ç¿ëÇÑ´Ù¸é ¿©·¯ Ŭ¶óÀÌ¾ðÆ®µéÀÌ µ¿½Ã¿¡ ¼¹ö¿¡ Á¢¼ÓÀ» ÇÒ ¼ö ¾ø½À´Ï´Ù. ÀÌ·¡¼´Â üÆÃ¼¹ö¸¦ ¸¸µé ¼ö ¾ø°ÚÁÒ. ÀÌ ¹®Á¦¸¦ ÇØ°áÇϱâ À§Çؼ´Â µÎ°¡Áö ¹æ¹ýÀÌ Àִµ¥...
¡¤fork()¸¦ ÀÌ¿ëÇØ¼ ÀÚ½Ä ÇÁ·Î¼¼¼¸¦ ¸¸µç´Ù.
¡¤thread ¿©·¯°³¸¦ ¸¸µé¾î »ç¿ëÇÑ´Ù.
Àú´Â thread¸¦ ÃßõÇÕ´Ï´Ù. ´õ °£ÆíÇϱ⠶§¹®ÀÌÁÒ. ¼Óµµµµ ´õ ºü¸£°í, java¿¡¼ »ç¿ëÇÏ´Â ¹æ¹ýÀ̱⵵ ÇÕ´Ï´Ù. (Àú´Â ¸ÖƼ¾²·¹µùÀ» java¿¡¼ óÀ½ Á¢Çß½À´Ï´Ù.) ¶ÇÇÑ Àü¿ª º¯¼ö¸¦ °øÀ¯ ÇÒ ¼ö ÀÖ¾î¼ °£ÆíÇÕ´Ï´Ù.
thread?
thread¶õ "ÇÁ·Î±×·¥ÀÇ È帧" À̶õ ¶æÀÔ´Ï´Ù.
À§ÀÇ °æ¿ì´Â ÇϳªÀÇ ¾²·¹µå ¸¸À» ¾²´Â °æ¿ìÀÔ´Ï´Ù. ¸ÖƼ¾²·¹µå´Â ¸» ±×´ë·Î ¾²·¹µå¸¦ ¿©·¯ °³ ¸¸µå´Â °ÍÀÔ´Ï´Ù.
#include <pthread.h>
int pthread_create(pthread_t *tid,const pthread_attr_t *attr, void * ( * start_routine)(void *), void *arg);
pthread_create ´Â ¾²·¹µå¸¦ Çϳª »ý¼ºÇÕ´Ï´Ù. tid ´Â ¾²·¹µåÀÇ idÀÔ´Ï´Ù. attrÀº ¾²·¹µåÀÇ ¼Ó¼ºÀ» ÁöÁ¤ÇØÁÝ´Ï´Ù. µðÆúÆ®·Î ÇÒ·Á¸é null. start_routine Àº ÇÔ¼ö¸¦ ÁöÁ¤ÇØ ÁÝ´Ï´Ù. start_routineÀº arg¸¦ ¸®ÅϰªÀº voidÀÔ´Ï´Ù.
#include <pthread.h>
void pthread_exit(void *value_ptr);
int pthread_join (pthread_t thread, void **value_ptr);
pthread_t pthread_self();
pthread_exit´Â ¾²·¹µå¸¦ ÁߴܽÃŵ´Ï´Ù. value_ptrÀº ¸®ÅÏÇÒ °ªÀÔ´Ï´Ù. pthread_join Àº thread°¡ ³¡³¯ ¶§ ±îÁö ±â´Ù¸³´Ï´Ù. value_ptr Àº ¸®ÅϰªÀ» ÀúÀåÇÒ °ðÀ» ÁöÁ¤ÇØ ÁÝ´Ï´Ù. pthread_self() ´Â ¾²·¹µå ÀÚ½ÅÀÇ ¾²·¹µå ¾ÆÀ̵𸦠³Ñ°ÜÁÝ´Ï´Ù.
¿¹Á¦) ¾²·¹µå¸¦ ¸¸µç ÈÄ hello world¸¦ ÃâÇõÇÏ´Â ÇÁ·Î±×·¥
#include <pthread.h>
void *hello_world (void *arg)
{
printf ("hello world\n");
return null;
}
int main (int argc, char *argv[])
{
pthread_t hello_id;
int status;
status = pthread_create (&hello_id, null, hello_world, null);
status = pthread_join (hello_id, null);
return 0;
}
äÆÃ ¼¹ö¸¦ ¸¸µéÀÚ!
äÆÃ ¼¹ö ¼Ò½º
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <stdlib.h>
#define maxuser 30
int tid;
const char welcome[] = "welcome to cph]['s chating server\n";
const char nick[] = "enter your nickname please?\n\r";
int ulist[maxuser];
int sockfd;
static int ct=0;
void *th(void *arg) {
int sock;
char buf[300];
int nrd,i;
int id;
char nik[80];
id = ct;
ct++;
sock = *((int *)arg);
ulist[id] = sock;
write(sock,nick,sizeof(nick));
read(sock,nik,300);
while(1) {
nrd = read(sock,buf,300);
// printf("%i\n",nrd);
if(((buf[0]=='q')&&(buf[1]=='!'))||(nrd==0)) {
break;
}
for(i=0;i<ct;i++) {
write(ulist[i],nik,strlen(nik)-2);
write(ulist[i]," : ",3);
write(ulist[i],buf,nrd);
}
}
for(i=id;i<ct;i++) {
ulist[i]=ulist[i+1];
}
ct--;
// printf("ct is : %i\n",ct);
close(sock);
// printf("good bye!\n");
}
void catch_ctrl_c(int signo) {
int i;
for(i=0;i<ct;i++) {
close(ulist[i]);
}
close(sockfd);
raise(9);
}
main(int argc,char *argv[]) {
int new_sockfd ,clilen,childpid,i,flag;
struct sockaddr_in cli_addr, serv_addr;
int port = 7250;
struct sigaction act;
act.sa_handler = catch_ctrl_c;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
sigaction(sigint, &act, null);
printf("cph]['s very simple chating server beta 0.0.1\n");
if(argc==2) {
port = atoi(argv[1]);
}
sockfd = socket(af_inet,sock_stream,0);
// bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = af_inet;
serv_addr.sin_addr.s_addr = htonl(inaddr_any);
serv_addr.sin_port = htons(port);
if(bind(sockfd, (struct sockaddr *)&serv_addr,sizeof(serv_addr))<0) {
perror("server bind error");
exit(1);
}
listen(sockfd, maxuser);
while(1) {
clilen = sizeof(cli_addr);
if((new_sockfd = accept(sockfd,(struct sockaddr *) &cli_addr, &clilen))<0) {
perror("accept error\n");
exit(1);
}
// printf("ok! new_sockfd = %i\n",new_sockfd);
pthread_create(&tid,0,th,(void *)&new_sockfd);
}
}
mutex
¸ÖƼ ¾²·¹µå ÇÁ·Î±×·¥À» ¸¸µé ¶§ÀÇ ¹®Á¦Á¡ ÁßÀÇ Çϳª´Â ¸Þ¸ð¸®¸¦ °øÀ¯ÇÒ ¶§¿¡ ¼ø¼ ¾øÀÌ Á¦¾î¸¦ ÇÏ´Ùº¸¸é ¾û¸ÁÀÌ µÇ¾î ¹ö¸®´Â °ÍÀÔ´Ï´Ù. ÀÌ·± ÀÏÀ» ÇØ°áÇϱâ À§ÇÑ °Í¿¡´Â mutex ¿Í condition variable, ±×¸®°í ÀüÅëÀûÀÎ ¹æ¹ýÀÎ semaphore°¡ ÀÖ½À´Ï´Ù.
mutex ´Â "mutual" °ú "exclusion" ÀÇ ÇÕ¼º¾îÀÔ´Ï´Ù. ÀÌ ¸ÞÄ¿´ÏÁòÀÇ ¿äÁ¡Àº ÇÑ ¸Þ¸ð¸®¿¡ ¿©·¯ ¾²·¹µå°¡ µ¿½Ã¿¡ Á¦¾îÇÒ ¼ö ¾ø°Ô ¸¸µå´Â °ÍÀÔ´Ï´Ù. mutex ´Â pthread_mutex_lock(); À¸·Î ´Ù¸¥ ¾²·¹µåÀÇ Á¦¾î¸¦ ¸·°í pthread_mutex_unlock(); À¸·Î ´Ù¸¥ ¾²·¹µåÀÇ Á¦¾î¸¦ Çã¿ëÇØ¾ß ÇÕ´Ï´Ù.
mutex¿¡ ÀÇÇØ º¸È£µÇ´Â º¯¼öµéÀº ¹Ýµå½Ã pthread_mutex_lock()À» ÇÑ ÈÄ¿¡ Á¦¾î¸¦ ÇØ¾ß ÇÕ´Ï´Ù.
#include <pthread.h>
pthread_mutex_lock(pthread_mutex_t m);
pthread_mutex_unlock(pthread_mutex_t m);
pthread_mutex_trylock(pthread_mutex_t m);
pthread_mutex_lock() Àº mutex¸¦ lockÇϱâ À§ÇØ ½ÃµµÇÕ´Ï´Ù. ¸¸¾à ´Ù¸¥ ¾²·¹µå°¡ mutex¸¦ lock ÇÑ »óŶó¸é unlock µÇ±â±îÁö ±â´Ù¸³´Ï´Ù. pthread_mutex_trylock() ¶ÇÇÑ lock() °ú ºñ½ÁÇÏÁö¸¸ unlock µÇ±â±îÁö ±â´Ù¸®Áö ¾Ê°í lock ÀÌ ¾ÈµÇ¾úÀ¸¸é À» ¸®ÅÏ ÇÕ´Ï´Ù.
pthread_mutex_t ´Â mutexÀÇ Á¤º¸¸¦ ´ã°í ÀÖ´Â ÀÚ·áÇüÀÔ´Ï´Ù. pthread_mutex_initialize ¶ó´Â ¸ÅÅ©·Î¸¦ ÀÌ¿ëÇØ¼ ÃʱâÈ ÇÒ ¼öµµ ÀÖ°í, pthread_mutex_init()¸¦ ÅëÇØ ÃʱâÈ ÇÒ ¼ö ÀÖ½À´Ï´Ù. µ¿ÀûÀ¸·Î ÇÏ·ÁÇϰųª, Ư¼öÇÑ ¼Ó¼ºÀ» ºÎ¿©ÇÏ·Á¸é pthread_mutex_init()¸¦ »ç¿ëÇÕ´Ï´Ù.
mutex¸¦ »ç¿ëÇÑ Ã¤ÆÃ ¼¹ö
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <stdlib.h>
#define maxuser 30
int tid;
const char welcome[] = "welcome to cph]['s chating server\n";
const char nick[] = "enter your nickname please?\n\r";
int ulist[maxuser];
pthread_mutex_t ulist_mutex = pthread_mutex_initializer;
pthread_mutex_t arg_mutex = pthread_mutex_initializer;
int sockfd,commfd;
static int ct=0;
void *th(void *arg) {
char buf[300];
int nrd,i;
int id;
char nik[80];
int *sc,sock;
sc = (int *)arg;
pthread_mutex_lock(&arg_mutex);
sock = sc[0];
pthread_mutex_unlock(&arg_mutex);
pthread_mutex_lock(&ulist_mutex);
id = ct;
ct++;
ulist[id] = sock;
pthread_mutex_unlock(&ulist_mutex);
write(sock,nick,sizeof(nick));
read(sock,nik,300);
while(1) {
nrd = read(sock,buf,300);
// printf("%i\n",nrd);
if(((buf[0]=='q')&&(buf[1]=='!'))||(nrd==0)) {
break;
}
pthread_mutex_lock(&ulist_mutex);
for(i=0;i<ct;i++) {
write(ulist[i],nik,strlen(nik)-2);
write(ulist[i]," : ",3);
write(ulist[i],buf,nrd);
}
pthread_mutex_unlock(&ulist_mutex);
}
pthread_mutex_lock(&ulist_mutex);
for(i=id;i<ct;i++) {
ulist[i]=ulist[i+1];
}
ct--;
pthread_mutex_unlock(&ulist_mutex);
// printf("ct is : %i\n",ct);
close(sock);
// printf("good bye!\n");
}
void catch_ctrl_c(int signo) {
int i;
pthread_mutex_lock(&ulist_mutex);
printf("ok\n");
for(i=0;i<ct;i++) {
close(ulist[i]);
}
ct = 0;
pthread_mutex_unlock(&ulist_mutex);
close(commfd);
close(sockfd);
raise(9);
}
main(int argc,char *argv[]) {
int new_sockfd ,clilen,childpid,i,flag;
struct sockaddr_in cli_addr, serv_addr;
int port = 7250;
int fa[1];
struct sigaction act;
act.sa_handler = catch_ctrl_c;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
sigaction(sigint, &act, null);
printf("cph]['s very simple chating server beta 0.0.1\n");
if(argc==2) {
port = atoi(argv[1]);
}
sockfd = socket(af_inet,sock_stream,0);
// bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = af_inet;
serv_addr.sin_addr.s_addr = htonl(inaddr_any);
serv_addr.sin_port = htons(port);
if(bind(sockfd, (struct sockaddr *)&serv_addr,sizeof(serv_addr))<0) {
perror("server bind error");
exit(1);
}
commfd = listen(sockfd, maxuser);
while(1) {
clilen = sizeof(cli_addr);
if((new_sockfd = accept(sockfd,(struct sockaddr *) &cli_addr, &clilen))<0) {
perror("accept error\n");
exit(1);
}
fa[0] = new_sockfd;
pthread_create(&tid,0,th,(void *)fa);
}
}
condition variable
condition variable ´Â º¯¼öÀÇ »ç¿ë°ú °ü·ÃµÈ ÀÏÁ¾ÀÇ Åë½Å ¸ÞÄ¿´ÏÁòÀÔ´Ï´Ù. °øÀ¯ÇÏ´Â ¸Þ¸ð¸®¸¦ Á¦¾îÇϰíÀÚ ÇÏ´Â ¾²·¹µå°¡ ¸Þ¸ð¸®°¡ ÇÊ¿äÇÑ Á¶°Ç¿¡ ¸ÂÁö¸¦ ¾ÊÀ» ¶§ (¿¹¸¦ µé¾î Å¥°¡ ²Ë ãÀ» ¶§) ¾²·¹µå´Â Á¶°ÇÀÇ »óŰ¡ ¹Ù²î±â¸¦ ±â´Ù¸³´Ï´Ù. ´Ù¸¥ ¾²·¹µå°¡ ¸Þ¸ð¸®°¡ ¹Ù²î¾úÀ½À» ¾Ë·ÁÁÖ¸é (signal) »ç¿ëÀ» ±â´Ù¸®´ø ¾²·¹µå´Â ´Ù½Ã Á¶°ÇÀ» °Ë»çÇϰí, Á¶°ÇÀÌ ¸ÂÀ¸¸é »ç¿ëÇÕ´Ï´Ù.
thread a :
1 pthread_mutex_lock(&mu);
2 while(x != y) pthread_cond_wait(&v,&mu);
3 /* x¿Í y¿¡ °üÇÑ ÀÏ */
4 pthread_mutex_unlock(&mu);
À§ÀÇ ¿¹Á¦¿¡¼ ¾²·¹µå°¡ ÀÛ¾÷À» °è¼ÓÇϱâ À§Çؼ ÇÊ¿äÇÑ Á¶°ÇÀº x == yÀÔ´Ï´Ù. (ÁÖÀÇ : while ¹®À̹ǷΠx != y °¡ °ÅÁþÀÏ ¶§ ±îÁö ±â´Ù¸³´Ï´Ù.) thread a ´Â mutex mu¸¦ Àá±×°í Á¶°ÇÀ» °Ë»çÇÑ ÈÄ ½ÅÈ£¸¦ ±â´Ù¸³´Ï´Ù. ½ÅÈ£¸¦ ¹ÞÀ» ¶§ ±îÁö´Â 3¹ø ÇàÀ» ½ÇÇàÇÏÁö ¾Ê½À´Ï´Ù. ½ÅÈ£¸¦ ±â´Ù¸± ¶§´Â while À̳ª for µîÀÇ ¹Ýº¹¹®À» »ç¿ëÇØ¾ß ÇÕ´Ï´Ù. if ¹®Àº ÇÑ ¹ø ¹Û¿¡ ±â´Ù¸®Áö ¾ÊÀ¸¹Ç·Î ºÎÀûÇÕÇÕ´Ï´Ù.
thread b :
1 pthread_mutex_lock(&mu);
2 x++;
3 pthread_cond_signal(&v);
4 pthread_mutex_unlock(&mu);
broadcast ¿Í signal
¸¸¾à¿¡ ´ë±âÁßÀÎ ¾²·¹µåµéÀÌ °¢ÀÚ ´Ù¸¥ Á¶°ÇÀ» ¿øÇϰí ÀÖ´Ù¸é(¿¹¸¦ µé¾î ¾²·¹µå a´Â Å¥°¡ ²Ë Â÷±â¸¦, ¾²·¹µå b´Â Å¥¿¡ µ¥ÀÌÅͰ¡ Çϳªµµ ¾ø±â¸¦) broadcast¸¦ »ç¿ëÇØ ÁÝ´Ï´Ù. ¸¸¾à ±×·¸Áö ¾Ê´Ù¸é signalÀ» »ç¿ëÇÏ´Â °ÍÀÌ ´õ ´É·üÀûÀÔ´Ï´Ù.
mutex¿Í °°ÀÌ »ç¿ë
condition value´Â mutex¿Í °°ÀÌ »ç¿ëÇÕ´Ï´Ù. mutex¸¦ lock ÇÏ°í ´ë±â¸¦ ÇÏ°Ô µÇ¸é ´ë±â ÇÒ ¶§ mutex¸¦ Ç®¾îÁÝ´Ï´Ù. ´Ù½Ã ½ÅÈ£¸¦ ¹Þ°í return ÇÒ ¶§¿¡´Â mutex¸¦ lock ÇÑ »óÅ·Πµ¹¾Æ¿À°Ô µË´Ï´Ù. ¾²·¹µå°¡ ´ë±â¸¦ ÇÒ ¶§¿¡´Â ¹Ýµå½Ã mutex°¡ Àá°Ü ÀÖ¾î¾ß ÇÕ´Ï´Ù. ¸¸¾à ±×·¸Áö ¾Ê´Ù¸é wait ÇÏ´Â °úÁ¤¿¡¼ ´Ù¸¥ ¾²·¹µå¿Í °ãÃÄÁ®¼ ¿À·ù°¡ »ý±æ ¼öµµ ÀÖ½À´Ï´Ù.
#include <pthread.h>
pthread_cond_init();
pthread_cond_t¸¦ ÃʱâÈÇÕ´Ï´Ù. ¸ÅÅ©·Î pthread_cond_initializerµµ ÀÖ½À´Ï´Ù.
pthread_cond_signal();
wait¸¦ ÇϰíÀÖ´Â ÇϳªÀÇ ¾²·¹µå¿¡ ½ÅÈ£¸¦ ÁÝ´Ï´Ù.
pthread_cond_wait();
½ÅÈ£¸¦ ±â´Ù¸³´Ï´Ù.
pthread_cond_broadcast();
±â´Ù¸®°í ÀÖ´Â ¸ðµç ¾²·¹µå¿¡ ½ÅÈ£¸¦ ÁÝ´Ï´Ù.
#include <pthread.h>
#include <time.h>
typedef struct my_struct_tag {
pthread_mutex_t mutex; /* protects access to value */
pthread_cond_t cond; /* signals change to value */
int value; /* access protected by mutex */
} my_struct_t;
my_struct_t data = {
pthread_mutex_initializer, pthread_cond_initializer, 0};
int hibernation = 1; /* default to 1 second */
/*
* thread start routine. it will set the main thread's predicate
* and signal the condition variable.
*/
void *
wait_thread (void *arg)
{
int status;
sleep (hibernation);
status = pthread_mutex_lock (&data.mutex);
data.value = 1; /* set predicate */
status = pthread_cond_signal (&data.cond);
status = pthread_mutex_unlock (&data.mutex);
return null;
}
int main (int argc, char *argv[])
{
int status;
pthread_t wait_thread_id;
struct timespec timeout;
/*
* if an argument is specified, interpret it as the number
* of seconds for wait_thread to sleep before signaling the
* condition variable. you can play with this to see the
* condition wait below time out or wake normally.
*/
if (argc > 1)
hibernation = atoi (argv[1]);
/*
* create wait_thread.
*/
status = pthread_create (&wait_thread_id, null, wait_thread, null);
/*
* wait on the condition variable for 2 seconds, or until
* signaled by the wait_thread. normally, wait_thread
* should signal. if you raise "hibernation" above 2
* seconds, it will time out.
*/
timeout.tv_sec = time (null) + 2;
timeout.tv_nsec = 0;
status = pthread_mutex_lock (&data.mutex);
while (data.value == 0) {
status = pthread_cond_timedwait (
&data.cond, &data.mutex, &timeout);
if (status == etimedout) {
printf ("condition wait timed out.\n");
break;
}
}
if (data.value != 0)
printf ("condition was signaled.\n");
status = pthread_mutex_unlock (&data.mutex);
return 0;
}
thread-specific data
º¸ÅëÀÇ ÇÁ·Î±×·¥¿¡¼ ¾²´Â Àü¿ªº¯¼ö ó·³, ÇÑ ¾²·¹µå ¾È¾Æ¼ °øÀ¯ÇÒ ¼ö ÀÖ´Â º¯¼ö¸¦ ¸¸µé ¼ö ÀÖ½À´Ï´Ù. thread-specific data´Â °øÀ¯ÇÒ º¯¼öÀÇ Æ÷ÀÎÅ͸¦ ±â¾ï Çß´Ù°¡ µ¹·Á ÁÝ´Ï´Ù. ÇÁ·Î±×·¥¿¡¼´Â ÇϳªÀÇ thread-specific key ¸¸À» »ç¿ëÇÏÁö¸¸ °¢°¢ÀÇ ¾²·¹µå ¸¶´Ù key °¡ °¡¸®Å°´Â ÁÖ¼Ò°¡ ´Ù¸£°Ô µË´Ï´Ù. µû¶ó¼ °¢°¢ÀÇ ¾²·¹µå´Â ¾²·¹µå¸¸ÀÇ Àü¿ª º¯¼ö¸¦ °¡Áú ¼ö ÀÖ°Ô µË´Ï´Ù.
pthread_key_t key;
int pthread_key_create(pthread_key_y *key, void (*destructor)(void *));
int pthread_key_delete(pthread_key_t key);
int pthread_setspecific(pthread_key_t key, const void *value);
void *pthread_getspecific (pthread_key_t key);
key ´Â thread-specific key¸¦ ÀúÀåÇÏ´Â ±¸Á¶Ã¼ÀÔ´Ï´Ù. pthread_key_create´Â Ű Çϳª¸¦ destructor ¿Í ÇÔ²² ¸¸µì´Ï´Ù. pthread_key_delete ´Â key¸¦ »èÁ¦ÇÕ´Ï´Ù. pthread_setspecific Àº key °¡ ¾î¶² value¸¦ ÁöÁ¤ÇÏ°Ô ÇÒ °ÍÀΰ¡¸¦ Á¤ÇÏ°Ô ÇÕ´Ï´Ù. pthread_getspecific Àº key °ª¿¡ ÇØ´çÇÏ´Â º¯¼öÀÇ ÁÖ¼Ò¸¦ ¾ò¾î ¿É´Ï´Ù.
¿¹Á¦) thread-specific key
#include <pthread.h>
/*
* structure used as the value for thread-specific data key.
*/
typedef struct tsd_tag {
pthread_t thread_id;
char *string;
} tsd_t;
pthread_key_t tsd_key; /* thread-specific data key */
pthread_once_t key_once = pthread_once_init;
/*
* one-time initialization routine used with the pthread_once
* control block.
*/
void once_routine (void)
{
int status;
printf ("initializing key\n");
status = pthread_key_create (&tsd_key, null);
}
/*
* thread start routine that uses pthread_once to dynamically
* create a thread-specific data key.
*/
void *thread_routine (void *arg)
{
tsd_t *value;
int status;
status = pthread_once (&key_once, once_routine);
value = (tsd_t*)malloc (sizeof (tsd_t));
status = pthread_setspecific (tsd_key, value);
printf ("%s set tsd value %p\n", arg, value);
value->thread_id = pthread_self ();
value->string = (char*)arg;
value = (tsd_t*)pthread_getspecific (tsd_key);
printf ("%s starting...\n", value->string);
sleep (2);
value = (tsd_t*)pthread_getspecific (tsd_key);
printf ("%s done...\n", value->string);
return null;
}
void main (int argc, char *argv[])
{
pthread_t thread1, thread2;
int status;
status = pthread_create (
&thread1, null, thread_routine, "thread 1");
status = pthread_create (
&thread2, null, thread_routine, "thread 2");
pthread_exit (null);
}
destructor ¿¹Á¦
#include <pthread.h>
/*
* structure used as value of thread-specific data key.
*/
typedef struct private_tag {
pthread_t thread_id;
char *string;
} private_t;
pthread_key_t identity_key; /* thread-specific data key */
pthread_mutex_t identity_key_mutex = pthread_mutex_initializer;
long identity_key_counter = 0;
/*
* this routine is called as each thread terminates with a value
* for the thread-specific data key. it keeps track of how many
* threads still have values, and deletes the key when there are
* no more references.
*/
void identity_key_destructor (void *value)
{
private_t *private = (private_t*)value;
int status;
printf ("thread \"%s\" exiting...\n", private->string);
free (value);
status = pthread_mutex_lock (&identity_key_mutex);
identity_key_counter--;
if (identity_key_counter <= 0) {
status = pthread_key_delete (identity_key);
printf ("key deleted...\n");
}
status = pthread_mutex_unlock (&identity_key_mutex);
}
/*
* helper routine to allocate a new value for thread-specific
* data key if the thread doesn't already have one.
*/
void *identity_key_get (void)
{
void *value;
int status;
value = pthread_getspecific (identity_key);
if (value == null) {
value = malloc (sizeof (private_t));
if (value == null)
errno_abort ("allocate key value");
status = pthread_setspecific (identity_key, (void*)value);
}
return value;
}
/*
* thread start routine to use thread-specific data.
*/
void *thread_routine (void *arg)
{
private_t *value;
value = (private_t*)identity_key_get ();
value->thread_id = pthread_self ();
value->string = (char*)arg;
printf ("thread \"%s\" starting...\n", value->string);
sleep (2);
return null;
}
void main (int argc, char *argv[])
{
pthread_t thread_1, thread_2;
private_t *value;
int status;
/*
* create the tsd key, and set the reference counter to
* the number of threads that will use it (two thread_routine
* threads plus main). this must be done before creating
* the threads! otherwise, if one thread runs the key's
* destructor before any other thread uses the key, it will
* be deleted.
*
* note that there's rarely any good reason to delete a
* thread-specific data key.
*/
status = pthread_key_create (&identity_key, identity_key_destructor);
identity_key_counter = 3;
value = (private_t*)identity_key_get ();
value->thread_id = pthread_self ();
value->string = "main thread";
status = pthread_create (&thread_1, null,
thread_routine, "thread 1");
status = pthread_create (&thread_2, null,
thread_routine, "thread 2");
pthread_exit (null);
}
fork();
¸ÖƼ¾²·¹µå ÇÁ·Î±×·¥¿¡¼ fork();¸¦ »ç¿ëÇÒ °æ¿ì ±× ¶§ÀÇ ÇൿÀ» pthread_atfork()·Î Á¤ÀÇÇÒ ¼ö ÀÖ½À´Ï´Ù. ÀϹÝÀûÀ¸·Î prepare¿¡¼´Â ¸ðµç mutex¸¦ Àá±×°í, parent¿¡¼ÀÇ ¸ðµÎ unlock ÇÕ´Ï´Ù.
(ÁÖÀÇ) ¸ÖƼ ¾²·¹µå ÇÁ·Î±×·¥¿¡¼´Â fork(); »ç¿ëÀ» ÇÇÇÏ´Â °ÍÀÌ ÁÁ½À´Ï´Ù.
<¿¹Á¦ fork()¸¦ »ç¿ëÇÏ´Â ¿¹>
#include <sys/types.h>
#include <pthread.h>
#include <sys/wait.h>
pid_t self_pid; /* pid of current process */
pthread_mutex_t mutex = pthread_mutex_initializer;
void fork_prepare (void)
{
int status;
/*
* lock the mutex in the parent before creating the child,
* to ensure that no other thread can lock it (or change any
* associated shared state) until after the fork completes.
*/
status = pthread_mutex_lock (&mutex);
}
/*
* this routine will be called after executing the fork, within
* the parent process
*/
void fork_parent (void)
{
int status;
/*
* unlock the mutex in the parent after the child has been created.
*/
status = pthread_mutex_unlock (&mutex);
}
/*
* this routine will be called after executing the fork, within
* the child process
*/
void fork_child (void)
{
int status;
/*
* update the file scope "self_pid" within the child process, and unlock
* the mutex.
*/
self_pid = getpid ();
status = pthread_mutex_unlock (&mutex);
}
/*
* thread start routine, which will fork a new child process.
*/
void *thread_routine (void *arg)
{
pid_t child_pid;
int status;
child_pid = fork ();
/*
* lock the mutex -- without the atfork handlers, the mutex will remain
* locked in the child process and this lock attempt will hang (or fail
* with edeadlk) in the child.
*/
status = pthread_mutex_lock (&mutex);
status = pthread_mutex_unlock (&mutex);
printf ("after fork: %d (%d)\n", child_pid, self_pid);
if (child_pid != 0) {
waitpid (child_pid, (int*)0, 0);
}
return null;
}
int main (int argc, char *argv[])
{
pthread_t fork_thread;
int atfork_flag = 1;
int status;
if (argc > 1)
atfork_flag = atoi (argv[1]);
if (atfork_flag) {
status = pthread_atfork (fork_prepare, fork_parent, fork_child);
}
self_pid = getpid ();
status = pthread_mutex_lock (&mutex);
/*
* create a thread while the mutex is locked. it will fork a process,
* which (without atfork handlers) will run with the mutex locked.
*/
status = pthread_create (&fork_thread, null, thread_routine, null);
sleep (5);
status = pthread_mutex_unlock (&mutex);
status = pthread_join (fork_thread, null);
return 0;
}
stdio
pthread ¿¡¼´Â stdio¸¦ thread safe ·Î Á¤Çϰí ÀÖ½À´Ï´Ù. ±×·¯³ª stdio¸¦ ¿©·¯ ¾²·¹µå°¡ ¾µ·Á°í ´Þ·Áµé °æ¿ì (stdio »Ó¸¸ ¾Æ´Ï¶ó ´ëºÎºÐÀÇ file * ) ÀÌ»óÇÑ °á°ú°¡ ³ª¿Ã ¼ö ÀÖ½À´Ï´Ù. ÀÌ °ÍÀ» ¸·±â À§ÇÑ ÇÔ¼ö°¡ flockfile(file *); °ú funlockfile(file *);, ftrylockfile(file *) ÀÔ´Ï´Ù. µÎ °¡Áö°¡ ÀÛµ¿ÇÏ´Â ¿ø¸®´Â mutex¿Í Å©°Ô ´Ù¸£Áö ¾Ê½À´Ï´Ù. ¶ôÀ» °É¶§´Â ÀÔ·Â ½ºÆ®¸²À» ¸ÕÀú lock ÇØ ÁÖ°í, Ç®¶§´Â ±× ¹Ý´ë·Î Çϵµ·Ï posix ¹®¼¿¡¼ ±Ç°íÇϰí ÀÖ½À´Ï´Ù.
<¿¹Á¦> stdioÀÇ lock °ú unlock
#include <pthread.h>
/*
* this routine writes a prompt to stdout (passed as the thread's
* "arg"), and reads a response. all other i/o to stdin and stdout
* is prevented by the file locks until both prompt and fgets are
* complete.
*/
void *prompt_routine (void *arg)
{
char *prompt = (char*)arg;
char *string;
int len;
string = (char*)malloc (128);
flockfile (stdin);
flockfile (stdout);
printf (prompt);
if (fgets (string, 128, stdin) == null)
string[0] = '\0';
else {
len = strlen (string);
if (len > 0 && string[len-1] == '\n')
string[len-1] = '\0';
}
funlockfile (stdout);
funlockfile (stdin);
return (void*)string;
}
int main (int argc, char *argv[])
{
pthread_t thread1, thread2, thread3;
char *string;
int status;
status = pthread_create (
&thread1, null, prompt_routine, "thread 1> ");
status = pthread_create (
&thread2, null, prompt_routine, "thread 2> ");
status = pthread_create (
&thread3, null, prompt_routine, "thread 3> ");
status = pthread_join (thread1, (void**)&string);
printf ("thread 1: \"%s\"\n", string);
free (string);
status = pthread_join (thread2, (void**)&string);
printf ("thread 1: \"%s\"\n", string);
free (string);
status = pthread_join (thread3, (void**)&string);
printf ("thread 1: \"%s\"\n", string);
free (string);
return 0;
}
cancellation
cancellationÀº ÇöÀç ½ÇÇàÁßÀÎ ¾²·¹µå¸¦ ÁßÁö½Ãŵ´Ï´Ù. ÇÁ·Î¼¼¼¿¡°Ô sigint³ª sigkillÀÇ ½Ã±×³ÎÀ» ÁÖ´Â °Í°ú °°´Ù°í »ý°¢ÇÏ½Ã¸é µË´Ï´Ù. cancellation Àº µÎ °¡Áö ¹æ½ÄÀÌ Àִµ¥ deferred¿Í ºñµ¿±âÀû ¹æ¹ýÀÌ ÀÖ½À´Ï´Ù. deferred¹æ½ÄÀ¸·Î cancellationÀ» ÇÒ °æ¿ì¿¡´Â ¾²·¹µå°¡ pthread_testcancel() Çϱâ Àü¿¡´Â ¾²·¹µå°¡ ¸ØÃßÁö ¾Ê½À´Ï´Ù. ¹Ý¸é ºñµ¿±âÀû ¹æ¹ýÀº ¾²·¹µå°¡ ±× Áï½Ã ¸ØÃä´Ï´Ù. ²À ÇÊ¿äÇÏÁö ¾ÊÀº °æ¿ì¿¡´Â cancellationÀ» ¾²´Â °Í º¸´Ù´Â pthread_joinÀ» ½á¼ ¾²·¹µå°¡ ³¡³¯ ¶§ ±îÁö ±â´Ù¸®´Â °ÍÀÌ ´õ ¾ÈÀüÇÕ´Ï´Ù. ´Ü, ¹«ÇÑ·çÇÁ¸¦ µµ´Â ¾²·¹µå¸¦ ¸¸µé¾î¼ ÀÛ¾÷À» ÇÏ´Ù°¡ ÀÎÀ§ÀûÀ¸·Î ¸¶Ä¡°Ô ÇÏ´Â ÇÁ·Î±×·¥ °°Àº °æ¿ì¿¡´Â À¯¿ëÇÒ ¼ö ÀÖ½À´Ï´Ù.
int pthread_cancel(pthread_t thread);
int pthread_setcancelstate(int state, int *oldstate);
int pthread_setcanceltype(int type, int *oldtype);
void pthread_testcancel(void);
void pthread_cleanup_push(void (*routin)(void *), void *arg);
void pthread_cleanup_pop(int execute);
pthread_cancel Àº threadÀÇ ½ÇÇàÀ» ¸ØÃß°Ô ÇÕ´Ï´Ù. pthread_setcancelstate ´Â Ãë¼Ò°¡ ºÒ°¡´ÉÇÏ°Ô ÇÒ °ÇÁö(pthread_cancel_disable), °¡´É ÇÏ°Ô ÇÒ °ÇÁö(pthread_cancel_enable)¸¦ Á¤ÇÕ´Ï´Ù. state ¿¡´Â °¡´É, ºÒ°¡´É ¿©ºÎ¸¦, oldstate¿¡´Â ¼³Á¤ ÀÌÀüÀÇ »óŸ¦ ÀúÀåÇØ ÁÝ´Ï´Ù. pthread_setcanceltype´Â À§¿¡¼ ¼³¸íÇÑ cancel ÇüŸ¦ Á¤ÇØ ÁÝ´Ï´Ù. default ´Â deferredÀÔ´Ï´Ù. pthread_cancel_deferred, pthread_cancel_asynchronous. testcancel Àº À§¿¡¼ ¼³¸íÇÑ ´ë·ÎÀÔ´Ï´Ù. cleanup Àº Ãë¼Ò°¡ µÉ ¶§ ½ÇÇàÇÒ ÇÔ¼öµéÀ» ÁöÁ¤ÇÕ´Ï´Ù. cleanup_push ´Â ¾²·¹µå°¡ Ãë¼Ò°¡ µÉ ¶§ ½ÇÇàÇÒ ÇÔ¼ö(¿¹¸¦ µé¸é, mutex¸¦ unlock ÇÏ´Â..)¸¦ ½ºÅÿ¡ ÀúÀåÇÕ´Ï´Ù. cleanup_popÀº ½ºÅÿ¡¼ »©³À´Ï´Ù. execute °¡ 0ÀÌ ¾Æ´Ï¸é, ±× ÇÔ¼ö¸¦ ½ÇÇàÇÏ°í ³¡³À´Ï´Ù.
#include <pthread.h>
static int counter;
/*
* loop until cancelled. the thread can be cancelled only
* when it calls pthread_testcancel, which it does each 1000
* iterations.
*/
void *thread_routine (void *arg)
{
for (counter = 0; ; counter++)
if ((counter % 1000) == 0) {
pthread_testcancel ();
}
}
int main (int argc, char *argv[])
{
pthread_t thread_id;
void *result;
int status;
status = pthread_create (
&thread_id, null, thread_routine, null);
sleep (2);
status = pthread_cancel (thread_id);
status = pthread_join (thread_id, &result);
if (result == pthread_canceled)
printf ("thread cancelled at iteration %d\n", counter);
else
printf ("thread was not cancelled\n");
return 0;
}
deferred
deferred·Î ÇÏ´Â °æ¿ì¿¡´Â `cancel ¸í·ÉÀÌ µé¾î¿Ô´Ù' ´Â °ÍÀÌ Àü´ÞÀÌ µÇ°í testcancelÀ» ÇÏ°Ô µÇ¸é thread°¡ cancel µË´Ï´Ù. cancel ¸í·ÉÀº ´Ü¼øÇÑ ½Ã±×³Î°ú´Â ´Þ¸® ¹Ýµå½Ã ±× ¾²·¹µå°¡ cancel ÀÌ µÇ¾î¾ß ÇÕ´Ï´Ù. °ð cancel ÀÌ µé¾î¿Ô¾îµµ ±×³É Áö³ªÄ¥ ¼ö´Â ¾ø½À´Ï´Ù.
ÀϹÝÀûÀ¸·Î unix ¿¡¼´Â testcancel ¿Ü¿¡µµ sleep, mutex_lock µîÀÇ ÇÔ¼ö°¡ testcancel °ú °°Àº ÀÛ¿ëÀ» ÇÕ´Ï´Ù. mutex¸¦ Àá±Ù »óÅ¿¡¼ ¾²·¹µå°¡ cancel µÉ °æ¿ì¿¡´Â ±× mutex¸¦ Àá±×·Á°í ÇÏ´Â ´Ù¸¥ ¾²·¹µåµéÀº µ¥µå¶ô¿¡ °É¸®°Ô µÇ°í, °á±¹ ÇÁ·Î±×·¥ÀÌ Á¦´ë·Î µ¹¾Æ°¡Áö ¾Ê½À´Ï´Ù. ÀÌ·± ÀÏÀ» ÇÇÇϱâ À§Çؼ cleanupÀ» »ç¿ëÇÏ´øÁö cancel ¼Ó¼ºÀ» disable ·Î ¹Ù²ã¼ cancel ÀÌ ¾ÈµÇ°Ô °ÍÀÌ ÁÁ½À´Ï´Ù.
ºñµ¿±âÀû
ºñµ¿±âÀû ¹æ¹ýÀº ¾ðÁ¦µçÁö ¾²·¹µå¸¦ Ãë¼ÒÇÒ ¼ö ÀÖ½À´Ï´Ù. µû¶ó¼, Á¤»óÀûÀ¸·Î Á¾·áÇϱâ À§Çؼ´Â Áß¿äÇÑ ºÎºÐ¿¡¼´Â Ãë¼Ò°¡ ºÒ°¡´ÉÇÏ°Ô ¼³Á¤Çϰųª, cleanupÀ» ¼³Á¤ÇÏ´Â °ÍÀÌ ÁÁ½À´Ï´Ù. ºñµ¿±âÀû Ãë¼Ò ¹æ¹ýÀÌ ¼³Á¤µÇ¾î ÀÖ´Â »óÅ¿¡¼´Â, ¸®¼Ò½º¸¦ ¿ä±¸ÇÏ´Â ÇÔ¼öµéÀ» È£ÃâÇÏ´Â °Íµµ ÇÇÇØ¾ß ÇÕ´Ï´Ù. ¿¹¸¦ µé¾î malloc °¡ ½ÇÇà Áß¿¡ Ãë¼Ò µÇ´Â °æ¿ì¿¡´Â heap¿¡¼ ¸Þ¸ð¸®¸¦ ÇÒ´ç ¹Þ¾ÒÁö¸¸ ÁÖ¼Ò¸¦ ³Ñ°ÜÁÖÁö ¸øÇÏ°í ³¡³ª¹ö¸®°Ô µË´Ï´Ù. ±×·¸°Ô µÈ´Ù¸é ±× ÇÁ·Î±×·¥¿¡¼´Â ÇÒ´çÀ» ¾îµð¿¡ ¹Þ¾Ò´ÂÁö ¾Ë ¼ö ¾ø°Ô µÇ¾î ¹®Á¦°¡ µË´Ï´Ù.
µû¶ó¼, ÇÔ¼ö¸¦ È£ÃâÇÒ ¶§¿¡´Â ±× ÇÔ¼ö°¡ ¾ÈÀüÇÑÁö¸¦ ¹Ýµå½Ã ¾Ë¾Æº» ÈÄ¿¡ È£ÃâÀ» ÇØ¾ß ÇÕ´Ï´Ù. pthread ÇÔ¼öµé Áß¿¡¼ ºñµ¿±âÀûÀÎ ¹æ¹ý¿¡ ¾ÈÀüÇÑ ÇÔ¼ö´Â pthread_cancel(), pthread_setcancelstate, pthread_setcanceltype »ÓÀÔ´Ï´Ù.
<¿¹Á¦> deffered
#include <pthread.h>
static int counter;
/*
* thread start routine.
*/
void *thread_routine (void *arg)
{
int state;
int status;
for (counter = 0; ; counter++) {
/*
* each 755 iterations, disable cancellation and sleep
* for one second.
*
* each 1000 iterations, test for a pending cancel by
* calling pthread_testcancel().
*/
if ((counter % 755) == 0) {
status = pthread_setcancelstate (
pthread_cancel_disable, &state);
sleep (1);
status = pthread_setcancelstate (
state, &state);
} else
if ((counter % 1000) == 0)
pthread_testcancel ();
}
}
int main (int argc, char *argv[])
{
pthread_t thread_id;
void *result;
int status;
status = pthread_create (
&thread_id, null, thread_routine, null);
sleep (2);
status = pthread_cancel (thread_id);
status = pthread_join (thread_id, &result);
if (result == pthread_canceled)
printf ("thread cancelled at iteration %d\n", counter);
else
printf ("thread was not cancelled\n");
return 0;
}
<¿¹Á¦> ºñµ¿±âÀû
#include <pthread.h>
#define size 10 /* array size */
static int matrixa[size][size];
static int matrixb[size][size];
static int matrixc[size][size];
/*
* loop until cancelled. the thread can be cancelled at any
* point within the inner loop, where asynchronous cancellation
* is enabled. the loop multiplies the two matrices matrixa
* and matrixb.
*/
void *thread_routine (void *arg)
{
int cancel_type, status;
int i, j, k, value = 1;
/*
* initialize the matrices to something arbitrary.
*/
for (i = 0; i < size; i++)
for (j = 0; j < size; j++) {
matrixa[i][j] = i;
matrixb[i][j] = j;
}
while (1) {
/*
* compute the matrix product of matrixa and matrixb.
*/
status = pthread_setcanceltype (
pthread_cancel_asynchronous,
&cancel_type);
for (i = 0; i < size; i++)
for (j = 0; j < size; j++) {
matrixc[i][j] = 0;
for (k = 0; k < size; k++)
matrixc[i][j] += matrixa[i][k] * matrixb[k][j];
}
status = pthread_setcanceltype (
cancel_type,
&cancel_type);
/*
* copy the result (matrixc) into matrixa to start again
*/
for (i = 0; i < size; i++)
for (j = 0; j < size; j++)
matrixa[i][j] = matrixc[i][j];
}
}
int main (int argc, char *argv[])
{
pthread_t thread_id;
void *result;
int status;
status = pthread_create (
&thread_id, null, thread_routine, null);
sleep (1);
status = pthread_cancel (thread_id);
status = pthread_join (thread_id, &result);
if (status != 0)
err_abort (status, "join thread");
if (result == pthread_canceled)
printf ("thread cancelled\n");
else
printf ("thread was not cancelled\n");
return 0;
}
<¿¹Á¦> cleanup
#include <pthread.h>
#define threads 5
/*
* control structure shared by the test threads, containing
* the synchronization and invariant data.
*/
typedef struct control_tag {
int counter, busy;
pthread_mutex_t mutex;
pthread_cond_t cv;
} control_t;
control_t control =
{0, 1, pthread_mutex_initializer, pthread_cond_initializer};
/*
* this routine is installed as the cancellation cleanup
* handler around the cancellable condition wait. it will
* be called by the system when the thread is cancelled.
*/
void cleanup_handler (void *arg)
{
control_t *st = (control_t *)arg;
int status;
st->counter--;
printf ("cleanup_handler: counter == %d\n", st->counter);
status = pthread_mutex_unlock (&st->mutex);
}
/*
* multiple threads are created running this routine (controlled
* by the threads macro). they maintain a "counter" invariant,
* which expresses the number of running threads. they specify a
* nonzero value to pthread_cleanup_pop to run the same
* "finalization" action when cancellation does not occur.
*/
void *thread_routine (void *arg)
{
int status;
pthread_cleanup_push (cleanup_handler, (void*)&control);
status = pthread_mutex_lock (&control.mutex);
control.counter++;
while (control.busy) {
status = pthread_cond_wait (&control.cv, &control.mutex);
}
pthread_cleanup_pop (1);
return null;
}
int main (int argc, char *argv[])
{
pthread_t thread_id[threads];
int count;
void *result;
int status;
for (count = 0; count < threads; count++) {
status = pthread_create (
&thread_id[count], null, thread_routine, null);
}
sleep (2);
for (count = 0; count < threads; count++) {
status = pthread_cancel (thread_id[count]);
status = pthread_join (thread_id[count], &result);
if (result == pthread_canceled)
printf ("thread %d cancelled\n", count);
else
printf ("thread %d was not cancelled\n", count);
}
return 0;
}
Âü°íÇÑ Ã¥/ÀÎÅÍ³Ý »çÀÌÆ®
practical unix programming - a guide to concurrency, communication, and multithreading
1997, kay a. robbins/steven robbins
programming with posix threads
david r. butenhof
pthread tutorial <http://www.actcom.co.il/~choo/lupg/tutorials/>
¹°¸®Àû(!) µµ¿òÀ» ÁֽŠºÐ
ÀÌ ¿µÃ¶