-
Notifications
You must be signed in to change notification settings - Fork 0
xv6 LWP Wiki (2. LWP Result)
thread_create, thread_exit, thread_join이 올바르게 작동하는지 알아보기 위해서 아래와 같은 테스트 코드를 작성했습니다.
int k = 100;
void* loop(void* num)
{
thread_t thread6;
int i = 6;
char *retval[5];
retval[0] = "d";
static char *args[5];
args[0] = "hihihihihi";
args[1] = "ddddddd";
while(k-- > 0) {
printf(1, "%d\n", k);
}
thread_exit((void*)NULL);
return NULL;
}
int main(int argc, char* argv[])
{
int i = 1;
int j = 2;
int a = 3;
int b = 4;
int c = 5;
thread_t thread1;
thread_t thread2;
thread_t thread3;
thread_t thread4;
thread_t thread5;
char* retVal[5];
retVal[0] = "ls";
thread_create(&thread1, loop, &i);
thread_create(&thread2, loop, &j);
thread_create(&thread3, loop, &a);
thread_create(&thread4, loop, &b);
thread_create(&thread5, loop, &c);
thread_join(thread1, (void**)retVal);
thread_join(thread2, (void**)retVal);
thread_join(thread3, (void**)retVal);
thread_join(thread4, (void**)retVal);
thread_join(thread5, (void**)retVal);
exit();
}
이와 같은 유저프로그램이 올바르게 동작한다면 thread_join에서 자원이 회수되는 순서는 차례대로 1, 2, 3, 4, 5번일 것입니다. 각각의 tid값이 4번부터 시작했기 때문에 자원이 회수되는 tid 순서는 아래의 그림처럼 4, 5 , 6, 7, 7이 나옵니다.
그렇다면 thread_join(thread3, retval) 이 thread3을 제대로 회수하지 못하고 sleep 상태에 있다면 그 아래의 join구문들은 올바르게 작동하여야합니다. 이 상황이 올바르게 동작하는지 확인해보겠습니다.
위의 코드에서 loop 함수를 아래와같이 변경했습니다.
3번 thread에서 while문 무한 loop를 돌기 때문에 thread_exit이 호출되지 않고 thread_join(thread3, retval)은 올바르게 자원을 회수하지 못한채 sleep 상태에 머물 것 입니다.
이에 따른 결과를 보겠습니다.
int k = 100;
void* loop(void* num)
{
thread_t thread6;
int i = 6;
char *retval[5];
retval[0] = "d";
static char *args[5];
args[0] = "hihihihihi";
args[1] = "ddddddd";
if(*(int*)num == 3) {
while(1) { };
}
while(k-- > 0) {
printf(1, "%d\n", k);
}
thread_exit((void*)NULL);
return NULL;
}
4, 5번 join 이후에 6번이 sleep 상태에 빠져있기 때문에 더이상 처리하지 못하고 무한 loop에 빠져있는 것을 볼 수 있습니다.
올바르게 exec이 작동하고, 단 하나의 thread만 남아있는지 알아보기 위해서 아래와 같은 코드를 작성했습니다.
아래의 코드가 올바르게 작동한다면 exec이 단 한번만 호출되고, 프로그램은 종료될 것 입니다.
그 이후에 확인했을 때 thread들의 자원은 회수되어있을 것 입니다.
void*
execthreadmain(void *arg)
{
char *args[3] = {"echo", "echo is executed!", 0};
printf(1, "execute start\n");
exec("echo", args);
printf(1, "panic at exec thread main\n");
thread_exit((void*)NULL);
exit();
}
int
main(int argc, char* argv[])
{
thread_t threads[THREADNUM];
int i;
void *retval;
for (i = 0; i < THREADNUM; i++){
if (thread_create(&threads[i], execthreadmain, (void*)0) != 0){
printf(1, "panic at thread_create\n");
return -1;
}
}
for (i = 0; i < THREADNUM; i++){
if (thread_join(threads[i], &retval) != 0){
printf(1, "panic at thread_join\n");
return -1;
}
}
printf(1, "panic at exectest\n");
return 0;
}
execute가 시작된 직후 쓰레드는 3, 4, 5, 6, 7, 8번이 존재했습니다.
thread를 정리하는 코드를 실행한 이후에 exec을 호출한 5번 쓰레두만 놔두고 나머지 쓰레드들을 모두 정리하였고 올바르게 execute가 실행된 것을 볼 수 있습니다.
exit과 kill을 호출했을 때 같은 pid값을 갖고있는 모든 thread들은 정리되어야합니다.
아래와 같은 exit, kill test 코드를 작성했습니다.
그에 따른 결과를 그림으로 확인해보겠습니다.
exit test code
int k = 100;
void* loop(void* num)
{
thread_t thread6;
int i = 6;
char *retval[5];
retval[0] = "d";
static char *args[5];
args[0] = "hihihihihi";
args[1] = "ddddddd";
if(*(int*)num == 3) {
exit();
}
while(k-- > 0) {
printf(1, "%d\n", k);
}
thread_exit((void*)NULL);
return NULL;
}
int main(int argc, char* argv[])
{
int i = 1;
int j = 2;
int a = 3;
int b = 4;
int c = 5;
thread_t thread1;
thread_t thread2;
thread_t thread3;
thread_t thread4;
thread_t thread5;
char* retVal[5];
retVal[0] = "ls";
thread_create(&thread1, loop, &i);
thread_create(&thread2, loop, &j);
thread_create(&thread3, loop, &a);
thread_create(&thread4, loop, &b);
thread_create(&thread5, loop, &c);
thread_join(thread1, (void**)retVal);
thread_join(thread2, (void**)retVal);
thread_join(thread3, (void**)retVal);
thread_join(thread4, (void**)retVal);
thread_join(thread5, (void**)retVal);
exit();
}
kill test code
int k = 100;
void* loop(void* num)
{
thread_t thread6;
int i = 6;
char *retval[5];
retval[0] = "d";
static char *args[5];
args[0] = "hihihihihi";
args[1] = "ddddddd";
if(*(int*)num == 3) {
kill(2);
}
while(k-- > 0) {
printf(1, "%d\n", k);
}
thread_exit((void*)NULL);
return NULL;
}
int main(int argc, char* argv[])
{
int i = 1;
int j = 2;
int a = 3;
int b = 4;
int c = 5;
thread_t thread1;
thread_t thread2;
thread_t thread3;
thread_t thread4;
thread_t thread5;
char* retVal[5];
retVal[0] = "ls";
thread_create(&thread1, loop, &i);
thread_create(&thread2, loop, &j);
thread_create(&thread3, loop, &a);
thread_create(&thread4, loop, &b);
thread_create(&thread5, loop, &c);
thread_join(thread1, (void**)retVal);
thread_join(thread2, (void**)retVal);
thread_join(thread3, (void**)retVal);
thread_join(thread4, (void**)retVal);
thread_join(thread5, (void**)retVal);
exit();
}
원래는 전역변수 k의 값 100이 0이 될 때 까지 모든 값이 출력되고, thread_join도 올바르게 작동하여 자원들이 회수되었다는 메세지가 출력되어야 합니다.
하지만 3번 쓰레드 생성과 동시에 start_routine에서 exit()과 kill(3)을 호출했기 때문에 모든 쓰레드들이 종료되어 아무 메세지도 출력하지 못하고, k값을 어느정도까지만 감소시키다가 종료합니다.
아래의 그림과 같이 남아있는 쓰레드들도 없는 결과를 볼 수 있습니다.