Á¦ 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/>

¹°¸®Àû(!) µµ¿òÀ» ÁֽŠºÐ

ÀÌ ¿µÃ¶