세마포어와 뮤텍스


*동기화 : 두 개 이상의 프로세스가 동일한 자원에 접근할 때 잘못된 연산을 없애고 일관성을 보장한다.


*세마포어

//    sem_test_a.c    // 


#include <stdio.h>

#include <semaphore.h>

#include <pthread.h>


sem_t        sem;  /*TODO: semaphore variable - sem */

pthread_t   task;


void Thread( void ) {

    int i = 0;

    int val;

  

    while(1) {

        i++;


        sem_wait( &sem ); /* TODO: take semaphore */


        sem_getvalue( &sem, &val ); /* get sem value to val */

        printf( "wakeup %d: value = %d\n", i ,val );

        

        if ( i > 5 ) break;

    }

}

//----------------------------------------

void main( void )

{

    int i = 0, j, val;


    sem_init( &sem, 0, 3 ); /* TODO: init unnamed semaphore */


    pthread_create( &task, NULL, (void*(*)(void*))Thread, NULL );

    

    while(1) {

        sleep(1);

        i++;


        printf( "sem post %d\n", i );

        sem_post( &sem ); /* TODO: give semaphore */


        sem_getvalue( &sem, &val ); /* get sem value to val */

        printf( "sem value = %d\n", val );


        if ( i > 5 ) break;

        

    }

}




# cc sem_test_a.c -lpthread

# ./a.out 


wakeup 1: value = 2

wakeup 2: value = 1

wakeup 3: value = 0

sem post 1

sem value = 1

wakeup 4: value = 0

sem post 2

sem value = 1

wakeup 5: value = 0

sem post 3

sem value = 1

wakeup 6: value = 0

sem post 4

sem value = 1

sem post 5

sem value = 2

sem post 6

sem value = 3


/*

현재 6번의 테스크가 실행되게 되어있다.


세마포어는 count가 0이되면 스레드는 block이 된다 (사용 불가능)    ==> sem_wait( &sem ); 가 block이 된다

wakeup 1: value = 2

wakeup 2: value = 1

wakeup 3: value = 0

부분에서 모두 사용 하였고


sem post 1       

sem value = 1

//이때는 반환을 하는 것을 출력하였는데 count가 증가한다 즉, 대기큐에 있는 프로세스들을 깨워 ready 큐로 이동한다. 그래서 count가 증가하여 value도 증가해서 1


wakeup 4: value = 0    //이때 또 task를 실행함으로써 count는 감소

sem post 2

sem value = 1

wakeup 5: value = 0

sem post 3

sem value = 1

wakeup 6: value = 0    //까지 반복한다.


sem post 5

sem value = 2

sem post 6

sem value = 3

//모든 테스크가 끝났을때를 보면 초기값인 value가 3까지 증가한다.



만약 main에서 while의 수가 늘어나면 세마포어는 생성되어진다.

*/






*뮤텍스 

잠김, 풀림으로 테스크 동기화 세마포어처럼 동작하나 소유권, 재귀적 접근, 테스크 삭제 보호,

우선 순위 역전 회피 프로토콜 등을 지원한다(생성시 옵션에 의해서 생성)


//    mutex_test_a.c    // 


#include <semaphore.h>

#include <pthread.h>

#include <sys/types.h>

#include <stdio.h>


/* TODO: define mutex variable and initialize */ 

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;


int val;

int arg1 = 0, arg2 = 1;


void *Thread( void* arg ) 

{

    int i, j;

    

    for( i = 0; ; i++ ) {

        /* TODO: lock   the mutex */

        pthread_mutex_lock( &mutex );


        val = *(int*)arg;

        printf( "thread %d: %dth iteration: val = %d\n", *(int*)arg, i, val);


        /* TODO: unlock the mutex */

        pthread_mutex_unlock( &mutex );


        sleep(1);

    }

pthread_exit(0);

}


int main( void ) {

    pthread_t  thread1, thread2;

    pthread_attr_t attr;

    

    pthread_attr_init( &attr );

    

    pthread_create( &thread1, &attr, (void*(*)(void*))Thread, &arg1 );

    pthread_create( &thread2, &attr, (void*(*)(void*))Thread, &arg2 );

    

    pthread_exit(0);


}




# cc mutex_test_a.c -lpthread

# ./a.out 

thread 1: 0th iteration: val = 1

thread 0: 0th iteration: val = 0

thread 1: 1th iteration: val = 1

thread 0: 1th iteration: val = 0

thread 1: 2th iteration: val = 1

thread 0: 2th iteration: val = 0

thread 1: 3th iteration: val = 1

thread 0: 3th iteration: val = 0

thread 1: 4th iteration: val = 1

thread 0: 4th iteration: val = 0

thread 1: 5th iteration: val = 1

thread 0: 5th iteration: val = 0

thread 0: 6th iteration: val = 0

thread 1: 6th iteration: val = 1







//    mutex_cond_a.c       //        Condition variable

 

#include <stdio.h>

#include <pthread.h>


pthread_t  thread;


pthread_mutex_t  mutex = PTHREAD_MUTEX_INITIALIZER;

pthread_cond_t   cond  = PTHREAD_COND_INITIALIZER;


int count = 0;


void* Thread ( void* arg ) {

    

    pthread_mutex_lock ( &mutex ); 

    

    while ( count < 5 ) {

        printf( "count = %d: wait...\n", count );


/*TODO: wait for condition variable signal  */

        pthread_cond_wait ( &cond, &mutex );

    }

    printf( "count = %d: done...\n", count );

    

    pthread_mutex_unlock ( &mutex );


    pthread_exit(0);

}


void main ( void ) {

    int i;



    pthread_create( &thread, NULL, (void*(*)(void*))Thread, NULL );

    

    for ( i = 0; i < 10; i++ ) {

        sleep(1);

        pthread_mutex_lock  ( &mutex );


        count++;


        /* TODO: signal condition variable 'cond' */ 

if (1) // check condition

pthread_cond_signal( &cond );


        printf( "condition signal %d\n", i );


        pthread_mutex_unlock( &mutex );

    }


    pthread_exit(0);

}




# ./a.out 

count = 0: wait...

condition signal 0

count = 1: wait...

condition signal 1

count = 2: wait...

condition signal 2

count = 3: wait...

condition signal 3

count = 4: wait...

condition signal 4

count = 5: done...

condition signal 5

condition signal 6

condition signal 7

condition signal 8

condition signal 9







■Thread




*스레드 생성 및 종료


//    pthread_test_q.c    //

#include <stdio.h>

#include <pthread.h>


int thread_args[3] = { 0, 1, 2 };                        /*스레드가 사용할 인자*/


void* Thread( void *arg )

{

    int i;

    for ( i=0; i<3; i++ )

        printf( "thread %d: %dth iteration\n", *(int*)arg, i );


//while(1); // TODO: hold here and try $ps -L


pthread_exit(0);

}


int main( void )

{

    int i, clock_get;

    pthread_t threads[3];         /*스레드 아이디 변수 */

    

    for ( i=0; i<3; i++ ) 

        // TODO: create a thread having Thread function 

        pthread_create( &threads[i],                

                        NULL,                      

                        ( void* (*)(void*) )Thread,

                        &thread_args[i] );

    

    while(1)sleep(1);

    

    //TODO: exit

    pthread_exit(0);

}


# cc pthread_test_q.c -lpthread

# ./a.out 


thread 2: 0th iteration

thread 2: 1th iteration

thread 2: 2th iteration

thread 1: 0th iteration

thread 1: 1th iteration

thread 1: 2th iteration

thread 0: 0th iteration

thread 0: 1th iteration

thread 0: 2th iteration

.....


thread 함수에 while(1); 
main에 while(1)sleep(1);

# ./a.out &
# ps -L

  PID   LWP TTY          TIME CMD
14150 14150 pts/0    00:00:00 a.out 
14150 14151 pts/0    00:00:01 a.out
14150 14152 pts/0    00:00:01 a.out
14150 14153 pts/0    00:00:01 a.out

thread 함수에 while(1); 
main에 while(1)sleep(1); 뺀 경우
# ./a.out &
# ps -L

  PID   LWP TTY          TIME CMD
14150 14150 pts/0    00:00:00 a.out <defunct>
14150 14151 pts/0    00:00:01 a.out
14150 14152 pts/0    00:00:01 a.out
14150 14153 pts/0    00:00:01 a.out

thread 함수에 while(1); 
main에 while(1)sleep(1);     pthread_exit(0);   뺀 경우


# ps -L

  PID   LWP TTY          TIME CMD

14061 14061 pts/0    00:00:00 bash

14439 14439 pts/0    00:00:00 ps


부모 프로세스가 끝나면 나머지 스레드들도 같이 끝난다.







*스레드 속성


//    pthread_attr_a.c    //

 

#include <stdio.h>

#include <pthread.h>

#include <sched.h>

#include <unistd.h>

#include <sys/types.h>


int thread_args[3] = { 0, 1, 2 };


void* Thread( void *arg )

{

    int i;

//    nice(10); // only for SCHED_NORMAL

for ( i=0; i<100; i++ ){

        printf( "%d", *(int*)arg);

    }


fflush(stdout); // try if you have not displayed 2s all enough !

//system("ps -l -L ");


sleep(100); //sleep for probe


    pthread_exit(0);  

}


int main( void ) {

    int i;

    pthread_t threads[3];

int policy;

  pid_t mypid;

    /*TODO: thread attribute variable here */

    pthread_attr_t  thread_attrs;


    /*TODO: thread schedule parameter here */

    struct sched_param  param;


mypid = getpid();


policy = sched_getscheduler(0); // get policy of self

printf("current policy is : %s \n", (policy==0) ? "SCHED_NORMAL" : (policy==1) ? "SCHED_FIFO" :(policy==2) ? "SCHED_RR" : "else" );

/*

#define SCHED_NORMAL            0

#define SCHED_FIFO              1

#define SCHED_RR                2

#define SCHED_BATCH             3

*/


#if 1

param.sched_priority = 30; /* 1 - 99 */

sched_setscheduler(mypid, SCHED_FIFO, &param);


policy = sched_getscheduler(0); // get policy of self

printf("current policy is : %s \n", (policy==0) ? "SCHED_NORMAL" : (policy==1) ? "SCHED_FIFO" :(policy==2) ? "SCHED_RR" : "else" );

#endif

    for ( i=0; i<3; i++ ) {

#if 1


/*

2 options of  : inherit( default: follow Mom's ) or explicit ( my own )

**/


/*TODO: initialize thread atrribute variable here */ 

        pthread_attr_init( &thread_attrs );


        /*TODO: set schedule policy : round-robin here */ 

        pthread_attr_setschedpolicy( &thread_attrs, SCHED_FIFO );  /* you can't change under inherit. just follow leader thread's **/


        /*TODO: set thread priority : 15 */   /* you can't change under inherit. just follow leader thread's **/

        param.sched_priority = 15;

        pthread_attr_setschedparam( &thread_attrs, &param );

#endif

        pthread_create( &threads[i], 

                        &thread_attrs, 

                        ( void* (*)(void*) )Thread, 

                        &thread_args[i] );


    }


    

system("ps -l -L ");

while(1)sleep(1);

    pthread_exit(0); 

}



<    user mode    >

$ cc pthread_attr_a.c -lpthread


$ ./a.out 

current policy is : SCHED_NORMAL 

current policy is : SCHED_NORMAL 

222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222211111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000F S   UID   PID  PPID   LWP  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD

0 S  1001  1430  1428  1430  0  80   0 -  1518 wait   pts/0    00:00:00 bash

0 S  1001  2151  1430  2151  0  80   0 -  6610 wait   pts/0    00:00:00 a.out

1 S  1001  2151  1430  2152  0  80   0 -  6610 hrtime pts/0    00:00:00 a.out

1 S  1001  2151  1430  2153  0  80   0 -  6610 hrtime pts/0    00:00:00 a.out

1 S  1001  2151  1430  2154  0  80   0 -  6610 hrtime pts/0    00:00:00 a.out

0 S  1001  2155  2151  2155  0  80   0 -   457 wait   pts/0    00:00:00 sh

0 R  1001  2156  2155  2156  0  80   0 -   625 -      pts/0    00:00:00 ps


 nice(10); 가 있으면


$ ./a.out 

current policy is : SCHED_NORMAL 

current policy is : SCHED_NORMAL                 ==>user mode라서 바뀌지 않는다.

222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222211111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

F S   UID   PID  PPID   LWP  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD

0 S  1001  1430  1428  1430  1  80   0 -  1518 wait   pts/0    00:00:00 bash

0 S  1001  1481  1430  1481  0  80   0 -  6610 wait   pts/0    00:00:00 a.out

1 S  1001  1481  1430  1482  0  90  10 -  6610 hrtime pts/0    00:00:00 a.out

1 S  1001  1481  1430  1483  0  90  10 -  6610 hrtime pts/0    00:00:00 a.out

1 S  1001  1481  1430  1484  0  90  10 -  6610 hrtime pts/0    00:00:00 a.out

0 S  1001  1485  1481  1485  0  80   0 -   457 wait   pts/0    00:00:00 sh

0 R  1001  1486  1485  1486  0  80   0 -   625 -      pts/0    00:00:00 ps


<    supervisor mode    >


# ./a.out 

current policy is : SCHED_NORMAL 

current policy is : SCHED_FIFO 

000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111112222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222

F S   UID   PID  PPID   LWP  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD

4 S     0  2157  1430  2157  3  80   0 -  1530 wait   pts/0    00:00:00 bash

4 S     0  2172  2157  2172  0  29   - -  6610 wait   pts/0    00:00:00 a.out

1 S     0  2172  2157  2173  0  29   - -  6610 hrtime pts/0    00:00:00 a.out

1 S     0  2172  2157  2174  0  29   - -  6610 hrtime pts/0    00:00:00 a.out

1 S     0  2172  2157  2175  0  29   - -  6610 hrtime pts/0    00:00:00 a.out

0 S     0  2176  2172  2176  0  29   - -   457 wait   pts/0    00:00:00 sh

4 R     0  2177  2176  2177  0  29   - -   625 -      pts/0    00:00:00 ps


















//    pthread_attr_a3.c    // 


/*

refer To:

https://www.systutorials.com/docs/linux/man/3-pthread_setschedparam/


*/


#include <pthread.h>

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

#include <errno.h>


#define handle_error_en(en, msg) \

        do { errno = en; perror(msg); exit(EXIT_FAILURE); } while (0)


static void

usage(char *prog_name, char *msg)

{

    if (msg != NULL)

        fputs(msg, stderr);


    fprintf(stderr, "Usage: %s [options]\n", prog_name);

    fprintf(stderr, "Options are:\n");

#define fpe(msg) fprintf(stderr, "\t%s", msg);          /* Shorter */

    fpe("-a<policy><prio> Set scheduling policy and priority in\n");

    fpe("                 thread attributes object\n");

    fpe("                 <policy> can be\n");

    fpe("                     f  SCHED_FIFO\n");

    fpe("                     r  SCHED_RR\n");

    fpe("                     o  SCHED_OTHER\n");

    fpe("-A               Use default thread attributes object\n");

    fpe("-i {e|s}         Set inherit scheduler attribute to\n");

    fpe("                 'explicit' or 'inherit'\n");

    fpe("-m<policy><prio> Set scheduling policy and priority on\n");

    fpe("                 main thread before pthread_create() call\n");

    exit(EXIT_FAILURE);

}


static int

get_policy(char p, int *policy)

{

    switch (p) {

    case 'f': *policy = SCHED_FIFO;     return 1;

    case 'r': *policy = SCHED_RR;       return 1;

    case 'o': *policy = SCHED_OTHER;    return 1;

    default:  return 0;

    }

}


static void

display_sched_attr(int policy, struct sched_param *param)

{

    printf("    policy=%s, priority=%d\n",

            (policy == SCHED_FIFO)  ? "SCHED_FIFO" :

            (policy == SCHED_RR)    ? "SCHED_RR" :

            (policy == SCHED_OTHER) ? "SCHED_OTHER" :

            "???",

            param->sched_priority);

}


static void

display_thread_sched_attr(char *msg)

{

    int policy, s;

    struct sched_param param;


    s = pthread_getschedparam(pthread_self(), &policy, &param);

    if (s != 0)

        handle_error_en(s, "pthread_getschedparam");


    printf("%s\n", msg);

    display_sched_attr(policy, &param);

}


static void *

thread_start(void *arg)

{

    display_thread_sched_attr("Scheduler attributes of new thread");


    return NULL;

}


int

main(int argc, char *argv[])

{

    int s, opt, inheritsched, use_null_attrib, policy;

    pthread_t thread;

    pthread_attr_t attr;

    pthread_attr_t *attrp;

    char *attr_sched_str, *main_sched_str, *inheritsched_str;

    struct sched_param param;


    /* Process command-line options */


    use_null_attrib = 0;

    attr_sched_str = NULL;

    main_sched_str = NULL;

    inheritsched_str = NULL;


    while ((opt = getopt(argc, argv, "a:Ai:m:")) != -1) {

        switch (opt) {

        case 'a': attr_sched_str = optarg;      break;

        case 'A': use_null_attrib = 1;          break;

        case 'i': inheritsched_str = optarg;    break;

        case 'm': main_sched_str = optarg;      break;

        default:  usage(argv[0], "Unrecognized option\n");

        }

    }


    if (use_null_attrib &&

            (inheritsched_str != NULL || attr_sched_str != NULL))

        usage(argv[0], "Can't specify -A with -i or -a\n");


    /* Optionally set scheduling attributes of main thread,

       and display the attributes */


    if (main_sched_str != NULL) {

        if (!get_policy(main_sched_str[0], &policy))

            usage(argv[0], "Bad policy for main thread (-s)\n");

        param.sched_priority = strtol(&main_sched_str[1], NULL, 0);


        s = pthread_setschedparam(pthread_self(), policy, &param);

        if (s != 0)

            handle_error_en(s, "pthread_setschedparam");

    }

    display_thread_sched_attr("Scheduler settings of main thread");

    printf("\n");


    /* Initialize thread attributes object according to options */


    attrp = NULL;


    if (!use_null_attrib) {

        s = pthread_attr_init(&attr);

        if (s != 0)

            handle_error_en(s, "pthread_attr_init");

        attrp = &attr;

    }


    if (inheritsched_str != NULL) {

        if (inheritsched_str[0] == 'e')

            inheritsched = PTHREAD_EXPLICIT_SCHED;

        else if (inheritsched_str[0] == 'i')

            inheritsched = PTHREAD_INHERIT_SCHED;

        else

            usage(argv[0], "Value for -i must be 'e' or 'i'\n");


        s = pthread_attr_setinheritsched(&attr, inheritsched);

        if (s != 0)

            handle_error_en(s, "pthread_attr_setinheritsched");

    }


    if (attr_sched_str != NULL) {

        if (!get_policy(attr_sched_str[0], &policy))

            usage(argv[0],

                    "Bad policy for 'attr' (-a)\n");

        param.sched_priority = strtol(&attr_sched_str[1], NULL, 0);


        s = pthread_attr_setschedpolicy(&attr, policy);

        if (s != 0)

            handle_error_en(s, "pthread_attr_setschedpolicy");

        s = pthread_attr_setschedparam(&attr, &param);

        if (s != 0)

            handle_error_en(s, "pthread_attr_setschedparam");

    }


    /* If we initialized a thread attributes object, display

       the scheduling attributes that were set in the object */


    if (attrp != NULL) {

        s = pthread_attr_getschedparam(&attr, &param);

        if (s != 0)

            handle_error_en(s, "pthread_attr_getschedparam");

        s = pthread_attr_getschedpolicy(&attr, &policy);

        if (s != 0)

            handle_error_en(s, "pthread_attr_getschedpolicy");


        printf("Scheduler settings in 'attr'\n");

        display_sched_attr(policy, &param);


        s = pthread_attr_getinheritsched(&attr, &inheritsched);

        printf("    inheritsched is %s\n",

                (inheritsched == PTHREAD_INHERIT_SCHED)  ? "INHERIT" :

                (inheritsched == PTHREAD_EXPLICIT_SCHED) ? "EXPLICIT" :

                "???");

        printf("\n");

    }


    /* Create a thread that will display its scheduling attributes */


    s = pthread_create(&thread, attrp, &thread_start, NULL);

    if (s != 0)

        handle_error_en(s, "pthread_create");


    /* Destroy unneeded thread attributes object */


    s = pthread_attr_destroy(&attr);

    if (s != 0)

        handle_error_en(s, "pthread_attr_destroy");


    s = pthread_join(thread, NULL);

    if (s != 0)

        handle_error_en(s, "pthread_join");


    exit(EXIT_SUCCESS);

}





<    supervisor mode    >


# ./a.out -mf10 -ar20 -i e

Scheduler settings of main thread

    policy=SCHED_FIFO, priority=10


Scheduler settings in 'attr'

    policy=SCHED_RR, priority=20

    inheritsched is EXPLICIT


Scheduler attributes of new thread

    policy=SCHED_RR, priority=20



# ./a.out -mf10 -ar20 -i i

Scheduler settings of main thread

    policy=SCHED_FIFO, priority=10


Scheduler settings in 'attr'

    policy=SCHED_RR, priority=20

    inheritsched is INHERIT


Scheduler attributes of new thread

    policy=SCHED_FIFO, priority=10




*스레드 join


//    pthread_join_a.c    // 

#include <pthread.h>

#include <stdlib.h>

#include <unistd.h>

#include <stdio.h>


void *thread_function(void *arg) { 

     int i; 

     for ( i=0; i<10; i++ ) { 

         printf("Thread : says hi! [%d]\n",i ); 

         sleep(1); 

     } 

     return NULL; 

}


int main(void) {


    pthread_t mythread;


    if ( pthread_create( &mythread, NULL, thread_function, NULL) ) {

       printf("error creating thread."); 

       abort(); 

    }


    if ( pthread_join ( mythread, NULL ) ) { //TODO: join mythread 

         printf("error joining thread."); 

         abort(); 

    }


    printf("main: finally joined \n");


}



join : mythread로 시작된 쓰레드가 종료되는걸 기다린다.

# ./a.out 

Thread : says hi! [0]

Thread : says hi! [1]

Thread : says hi! [2]

Thread : says hi! [3]

Thread : says hi! [4]

Thread : says hi! [5]

Thread : says hi! [6]

Thread : says hi! [7]

Thread : says hi! [8]

Thread : says hi! [9]

main: finally joined 



■Multiplexed I/O


1. 프로세스는 하나 이상의 file descriptor가 준비될 때 까지 Block에 들어감.

2. File descriptor 중 하나가 요청한 입출력 준비가 되면 시스템이 알려준다.

3. Block되어 있던 프로세스가 깨어난 후

4. 프로세스는 입출력 준비된 file descriptor들에 대해 처리한다.


//    select_test.c    //

#include <sys/time.h> 

#include <sys/types.h> 

#include <unistd.h> 

#include <fcntl.h> 

#include <stdlib.h> 

#include <string.h> 

#include <stdio.h> 


int main()

{

    int fd[2];

    int i;

    int n;

    int state;


    char buf[255];


    struct timeval tv;


    fd_set readfds, writefds;


    if ((fd[0] = open("testfile0", O_RDONLY)) == -1)

    {

        perror("file open error : ");

        exit(0);

    }

    if ((fd[1] = open("testfile1", O_RDONLY)) == -1)

    {

        perror("file open error : ");

        exit(0);

    }


    memset (buf, 0x00, 255);


    for(;;)

    {

        FD_ZERO(&readfds);

        FD_SET(fd[0], &readfds);

        FD_SET(fd[1], &readfds);


        state = select(fd[1]+1, &readfds, NULL, NULL, NULL);

        switch(state)

        {

            case -1:

                perror("select error : ");

                exit(0);

                break;


            default :

                for (i = 0; i < 2; i++)

                {

                    if (FD_ISSET(fd[i], &readfds))

                    {

                        while ((n = read(fd[i], buf, 255)) > 0)

                            printf("(%d) [%d] %s", state, i, buf);

                    }

                }

                memset (buf, 0x00, 255);

                break;

        }

        usleep(1000);

    }

}


# touch testfile0 testfile1
# cc seletc_test.c
# ./a.out &
[4] 11443
# echo hello >> testfile0
(2) [0] hello
echo word >> testfile1
(2) [1] word
echo good >> testfile0

# cat testfile0

hello

good

# cat testfile1

word



*입출력 리다이렉션
//    std.c    //

#include<unistd.h>
#include<sys/types.h>
#include<stdio.h>
#include<string.h>

#define STDIN 0
#define STDOUT 1
#define STDERR 2

#define ERRMSG "Devide Not Zero\n"

int main()
{
    int a;
    int b;
    char buf[80];

    read(STDIN, buf, 80);
    a = atoi(buf);

    read(STDIN, buf, 80);
    b = atoi(buf);
    if(b == 0)
    {
        write(STDERR, ERRMSG, strlen(ERRMSG));
        return 1;
    }

    sprintf(buf, "%d / %d = %d\n", a, b, (int)(a/b));

    write(STDOUT, buf, strlen(buf));
    return 0;
}

# cc std.c

# ./a.out


# ./a.out 

4

8

4 / 8 = 0


# ./a.out 

6

0

Devide Not Zero


# ./a.out 2>stderr.txt            -->2 : STDERR를 리다이렉션으로 stderr.txt에 저장
6
0
# cat stderr.txt 
Devide Not Zero

# ./a.out  1>stderr.txt
1
2
# cat stderr.txt 
1 / 2 = 0







■프로세스


//    fork.c    //
#include <stdio.h>
#include <stdlib.h> // for system()
#include <unistd.h> // for execl(), fork()
#include <wait.h>       // for wait()

int main(int argc, char *argv[])
{
    int pid;
    /* fork another process */
    pid = fork();
    if(pid < 0) {                       /* error occurred */
        fprintf(stderr,"Fork Failed");
        exit(-1);
    } else if (pid== 0) {       /* child process */
               // execl("/bin/ls", "ls", NULL);                ==>Child here! 없다
                //execl("/bin/ps", "ps", "aux", NULL);      ==>Child here! 없다
                //system("/bin/ps aux");                      ==>Child here! 없다있다
                printf("Child here!\n");
        //      for(;;) 
                sleep(1);
    } else {          /* parent process */
        wait(NULL);
        printf("Child Complete!\n");
        exit(0);
    }
}

# ./a.out 
Child here!
Child Complete!


 // execl("/bin/ls", "ls", NULL); 

# ./a.out 

a.out  execl.c fork.c orphan.c  prio.c  sched_param.c  wait.c  zombie.c

Child Complete!




*고아 프로세스 : 부모 프로세스가 먼저 종료된 경우 자동적으로 init의 상속이된다.


//    orphan.c    //

#include <sys/types.h>

#include <wait.h>

#include <stdio.h>


int main()

{

pid_t pid;

printf("I'm the original process : pid = %d, ppid = %d\n", 

getpid(), getppid());


pid =  fork();

if ( pid != 0 )  { /* parent process */

printf("I'm parent process : pid = %d, ppid = %d\n", 

getpid(), getppid());

printf("my child process : pid = %d\n", pid);

}

else { /* child process */

sleep(5);

printf("I'm child process : pid = %d, ppid = %d\n", 

getpid(), getppid());

}

/* parent & child  process */

printf("pid %d terminates.. \n", getpid());  

}



$ ./a.out 

I'm the original process : pid = 12382, ppid = 1623

I'm parent process : pid = 12382, ppid = 1623

my child process : pid = 12383

pid 12382 terminates.. 

$ ps -l

F S   UID   PID  PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD

0 S  1001  1623  1621  0  80   0 -  1518 wait   pts/0    00:00:00 bash

1 S  1001 12383     1  0  80   0 -   404 hrtime pts/0    00:00:00 a.out

0 R  1001 12386  1623  0  80   0 -   625 -      pts/0    00:00:00 ps







* 좀비 프로세스 : 실행이 종료되어 부모 프로세스가 반환 코드를 받을 때까지 프로세스 테이블 엔트리에 정보가 남아 있는 프로세스


//    Zombi.c    //

#include <sys/types.h>

#include <wait.h>

#include <stdlib.h>


int main()

{

   pid_t pid;

      

   pid = fork();


   if ( pid != 0 )  { /* parent process */

while(1) sleep(1000);

   }

   else { /* child  process */

exit(42);

   }


}



$ ./a.out &

[1] 12473

$ ps

  PID TTY          TIME CMD

 1623 pts/0    00:00:00 bash

12473 pts/0    00:00:00 a.out

12474 pts/0    00:00:00 a.out <defunct>

12475 pts/0    00:00:00 ps


$ kill 12473

$ ps

  PID TTY          TIME CMD

 1623 pts/0    00:00:00 bash

12478 pts/0    00:00:00 ps

[1]+  Terminated              ./a.out




*프로세스 상태 


//    prio.c    //


#include <stdio.h>

#include <sys/types.h>

#include <sys/resource.h>

#include <unistd.h>


int main(void)

{

//get process id of this process

pid_t current_pid = getpid();


//get priority   of this process

int priority = getpriority(PRIO_PROCESS, current_pid);        //nice값

printf("Process: %d, Priority: %d\n", current_pid, priority);

sleep(1);


/*

Try cases below... 


case 1: $ ./a.out &

$ ps -l

case 2: # ./a.out &

# ps -l

case 3: $ nice  -3 ./a.out &

$ ps -l

case 4: # nice --3 ./a.out &

# ps -l

/*결론 :  -3값은 sudo 권한만 가능 */

*/

/*  nice by +5 */

setpriority(PRIO_PROCESS, current_pid, 5);

priority = getpriority(PRIO_PROCESS, current_pid);

printf("Process: %d, Priority: %d\n", current_pid, priority);


system("ps -l");


sleep(1);


nice(-10); /* only superuser may lower priority */

priority = getpriority(PRIO_PROCESS, current_pid);

printf("Process: %d, Priority: %d\n", current_pid, priority);


system("ps -l");


return 0;

}



$ whoami

mds

$ cc prio.c 

$ ./a.out 


Process: 12723, Priority: 0

Process: 12723, Priority: 5

F S   UID   PID  PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD

0 S  1001  1623  1621  0  80   0 -  1519 wait   pts/0    00:00:00 bash

0 S  1001 12723  1623  0  85   5 -   404 wait   pts/0    00:00:00 a.out

0 S  1001 12724 12723  0  85   5 -   457 wait   pts/0    00:00:00 sh

0 R  1001 12725 12724  0  85   5 -   625 -      pts/0    00:00:00 ps

Process: 12723, Priority: 5

F S   UID   PID  PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD

0 S  1001  1623  1621  0  80   0 -  1519 wait   pts/0    00:00:00 bash

0 S  1001 12723  1623  0  85   5 -   404 wait   pts/0    00:00:00 a.out

0 S  1001 12726 12723  0  85   5 -   457 wait   pts/0    00:00:00 sh

0 R  1001 12727 12726  0  85   5 -   625 -      pts/0    00:00:00 ps


$ nice --3 ./a.out 
nice: cannot set niceness: Permission denied


# whoami

root

# cc prio.c 

# ./a.out 


Process: 12801, Priority: 0

Process: 12801, Priority: 5

F S   UID   PID  PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD

4 S     0 12769  1623  2  80   0 -  1533 wait   pts/0    00:00:00 bash

0 S     0 12801 12769  0  85   5 -   404 wait   pts/0    00:00:00 a.out

0 S     0 12802 12801  0  85   5 -   457 wait   pts/0    00:00:00 sh

4 R     0 12803 12802  0  85   5 -   625 -      pts/0    00:00:00 ps

Process: 12801, Priority: -5

F S   UID   PID  PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD

4 S     0 12769  1623  1  80   0 -  1533 wait   pts/0    00:00:00 bash

4 S     0 12801 12769  0  75  -5 -   404 wait   pts/0    00:00:00 a.out

0 S     0 12804 12801  0  75  -5 -   457 wait   pts/0    00:00:00 sh

4 R     0 12805 12804  0  75  -5 -   625 -      pts/0    00:00:00 ps







//    sched_param.c    //

#include <stdio.h>

#include <sys/types.h>

#include <sched.h>

#include <stdlib.h>

#include <unistd.h>


int main(void)

{

struct sched_param param;

int policy;

char *policy_name;


pid_t current_pid = getpid();

/*

only superuser may lower the priorities and change schedule

*/

sched_getparam(current_pid, &param);

param.sched_priority = 65;

sched_setscheduler(current_pid, SCHED_FIFO, &param);


sched_getparam(current_pid, &param);

policy = sched_getscheduler(current_pid);


if      (policy == 0) policy_name = "SCHED_OTHER";

else if (policy == 1) policy_name = "SCHED_FIFO";

else if (policy == 2) policy_name = "SCHED_RR";

else policy_name = "Unknown";

printf("Current PID: %d\n", (int)current_pid);

printf("Scheduling Policy: %d, %s\n", policy, policy_name );

printf("RT Sched Priority: %d  \n\n", param.sched_priority);


puts("#ps -l to check the priority");

sleep(100);


return 0;

}



# ./a.out &

[1] 12945

Current PID: 12945

Scheduling Policy: 1, SCHED_FIFO

RT Sched Priority: 65  


#ps -l to check the priority


# ps -l

F S   UID   PID  PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD

4 S     0 12893  1623  0  80   0 -  1535 wait   pts/0    00:00:00 bash

4 S     0 12945 12893  0  -6   - -   404 hrtime pts/0    00:00:00 a.out

4 R     0 12946 12893  0  80   0 -   625 -      pts/0    00:00:00 ps




■Makefile



*makefile 은 Rule로 이루어져 있다.


target : dependencies

<tab>command

target : command 부분이 실행되어 나온 결과 파일

dependencies : target을 만들기 위해 사용되는 파일

command : command의 시작은 반드시 tab후 명령어 사용


*기본 예제


//    bar.c    //

#include <stdio.h>


void bar(void)

{

printf("Good bye, my love \n");

}


//    foo.c    //

extern void bar(void);

int main(void)

{

bar();

return 0;

}

//    makefile    //

baz:foo.o      bar.o

gcc -o baz foo.o bar.o


foo.o:foo.c

gcc -c foo.c


bar.o:     bar.c

gcc -c bar.c



clean:

rm -f baz foo.o bar.o

# ./baz 

Good bye, my love 



*매크로와 라벨


# ls

func1.c  func2.c  io.h  main.c  makefile



//    func1.c    //

#include <stdio.h>


void func1()

{

printf("this is function1 program\n");

}


//    func2.c    //

#include <stdio.h>


void func2()

{

printf("this is function2 program\n");

}


//    main.c    //

#include <stdio.h>
#include "io.h"

int main()
{
printf("this is main program\n");
func1();
func2();
return 0;
}

//    makefile    //           

OBJECTS= main.o func1.o func2.o

TARGET= makeprog


$(TARGET): $(OBJECTS)

gcc -o $(TARGET) $(OBJECTS)


main.o: main.c

gcc -c main.c


func1.o: func1.c

gcc -c func1.c


func2.o: func2.c

gcc -c func2.c


clean:

rm -f $(TARGET) $(OBJECTS)


/*

매크로를 사용할때는 $() 사용

미리 정의된 매크로도 있다. 예)CC = gcc




OBJECTS= main.o func1.o func2.o

TARGET= makeprog

CC= gcc                                     //(CC : Macro)

CFLAGS= -c                                //c파일을 컴파일(CFLAGS : flag)

makeprog: $(OBJECTS)

$(CC) -o $(TARGET) $(OBJECTS)


main.o: main.c

$(CC) $(CFLAGS) main.c


func1.o: func1.c

$(CC) $(CFLAGS) func1.c


func2.o: func2.c

$(CC) $(CFLAGS) func2.c


clean:

rm -f $(TARGET) $(OBJECTS)


*/


*확장자 사용

.SUFFIXES = .c .o                            =>make가 어느확장자를 가진 파일들을 처리할 것인가

OBJECTS= main.o func1.o func2.o

SRCS= main.c func1.c func2.c

TARGET= makeprog

CC= gcc

CFLAGS= -g -c


$(TARGET):      $(OBJECTS)

        $(CC) -o $(TARGET) $(OBJECTS)


.c.o :

        $(CC) $(CFLAGS) $<                    =>확장자 규칙을 직접 구현


clean:

        rm -f $(TARGET) $(OBJECTS) core


main.o: io.h main.c

func1.o: io.h func1.c

func2.o: io.h func2.c



/*
직접구현이 안되어있을 때는 
밑에와 같이 자동으로 해준다.
.c.o : 
$(CC) $(CFLAGS) -c $< -o $@
*/

/*
$@ : target
$* : 확장자가 없는 target
$< : dependency 중 최근에 갱신된 파일
*/


■정적, 공유, 동적 라이브러리



라이브러리 : 자주 사용되는 기능들을 모듈 형태로 만들어 프로그램 유지보수 및 디버깅을 쉽게 할 수 있다.

  링크 단계에서 연결되거나 실행중 연결되기도 한다.




1. 정적 라이브러리 : 링크시에 포함되며 사이즈가 커지는 문제점이 발생


// mylib.h //

int sum(int a , int b);

int diff(int a, int b);


// mylib.c //

#include "mylib.h"

int sum(int a , int b)

{

return a+b;

}


int diff (int a, int b)

{

return a-b;

}


// main.c // 

#include "mylib.h"

#include <stdio.h>


int main()

{

int a, b;

a=100;

b=50;


printf("sum; %d\n", sum(a, b));

printf("diff: %d\n", diff(a,b));

return 0;

}


#gcc -c mylib.c                              =>mylib.o 오브젝트 파일 생성

#ar rc libmylib.a mylib.o                  =>아카이브 파일 생성
/*
r: replacement
c: create
*/
#gcc -o main main.c -L./ -lmylib       => -L은 라이브러리가 있는 경로, -l은 libmylib.a를 지정, 확장자 없이 라이브러리이름 넣어줍니다.

#./main                    




2. 공유 라이브러리

# gcc -fPIC -c ./lib/myfunc.c                                                             
/*
-fPIC : Position Independent Code
*/
# gcc -shared -W1,-soname,libmylib.so.1 -o libmylib.so.1.0.1 myfunc.o 
/*
-shared : 공유 라이브러리를 사용해서 링크
-W1 : warning level 1 에러시
-soname : 실제 만들 라이브러리인 libmylib.so.1.0.1 에 libmylib.so.1이라는 soname을 생성하여 나중에 
동적링크가 공유 라이브러리를 찾을때 soname인 libmylib.so.1를 찾아 링크 하도록 한다.
버전 관리를 융통성 있게 하기위함이고 gcc가 링크하는 파일명은 버전 정보가 없는 libmylib.so로 링크 파일 생성
*/
# cp libmylib.so.1.0.1 /usr/local/lib
# ln -s /usr/local/lib/libmylib.so.1.0.1 /usr/local/lib/libmylib.so
# gcc -o hello hello.c -L/usr/local/lib -lmylib
/*
libmylib.so를 찾으려면    -l옵션은 lib 를 기본적어로 붙여 찾는다. 그래서 -lmylib
*/
# export LD_LIBRARY_PATH = $LD_LIBRARY_PATH:/usr/local/lib
# ./hello


3. 동적 라이브러리
// dylib.c //
#include<stdio.h>
#include<dlfcn.h>

int main()
{
        int a=100,b=50;
        void *handle;
        char *error;
        int (*result)(int,int);

        handle = dlopen("./lib/libmylib.so.2",RTLD_NOW);

        if(!handle)
        {
                printf("open error\n");
                return 1;
        }

        result = dlsym(handle, "sum");
        if((error = dlerror()) !=NULL)
        {
                fputs(error,stderr);
                return 1;
        }
        else
        {
                printf("sum : %d\n",result(a,b));
        }
        dlclose(handle);
        return 0;
}


# gcc -o dylib dylib.c -ldl


■파일

*파일 열기
// open.c //

#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main()
{
int fd;
fd = open("hello.txt", O_CREAT|O_WRONLY, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP);
}

# cc open.c 
# ./a.out 
# ls -al hello.txt 
-rw-r----- 1 root root 0 2018-12-11 14:45 hello.txt
/*
파일이름 : hello.txt
파일이 없을 경우 생성
권한 640
*/



*파일 읽기

// fly.txt //
Fly me to the moon And let me play among the stars
Let me see what spring is like on Jupiter and Mars
In other words hold my hand
In other words darling kiss me
on Jupiter and Mars
In other words hold my hand

// read.c //
#include<stdlib.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>

#define MAXLEN 80
int main()
{
int fd;
int readn  =0;
char buf[MAXLEN];
fd = open("fly.txt", O_RDONLY);
if(fd <0)
{
perror("file open error:");
return 1;
}
memset(buf, 0x00, MAXLEN);
while((readn=read(fd, buf, MAXLEN-1))>0)
{
printf("%s", buf);
    memset(buf, 0x00, MAXLEN);
}
}

# cc read.c 
# ./a.out 


*파일 쓰기

#include <unistd.h>
#include<stdio.h>
#include <fcntl.h>
#include <string.h>

int main()
{
        int fd;
        int i;
        int wdata=0;
        int wsize=0;
        fd = open("data.txt", O_CREAT|O_WRONLY);
        if(fd<0)
        {
                perror("file open error");
                return -1;
        }
        for(i=0; i<100; i++)
        {
                wdata=i*2;
                wsize=write(fd, (void*)&wdata, sizeof(int));
                printf("Write %d(%d byte)\n", wdata, wsize);
        }
        close(fd);
}



*구조체 데이터 파일 읽기, 쓰기


// addr_make.c //

#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <stdio.h>

struct userInfo
{
  char name[28];
  int age;
  int sex;
  char hobby[28];
};

void makeUserInfo(struct userInfo *uinfo,
  char *name, // 이름
  int age,    // 나이
  int sex,    // 성 (남: 0, 여: 1)
  char *hobby) // 취미
{
  memset((void *)uinfo, 0x00, sizeof(struct userInfo));
  strcpy(uinfo->name, name);
  uinfo->age = age;
  uinfo->sex = sex;
  strcpy(uinfo->hobby, hobby);
}

int main()
{
  int fd;
  struct userInfo myAddrBook;
  fd = open("hello.txt", O_CREAT|O_WRONLY, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP);
  if (fd < 0)
  {
perror("file open error");
return 1;
  }

  makeUserInfo((void *)&myAddrBook, "user1", 19, 0, "programming");
  write(fd, (void *)&myAddrBook, sizeof(myAddrBook));

  makeUserInfo((void *)&myAddrBook, "user2", 22, 1, "playing games");
  write(fd, (void *)&myAddrBook, sizeof(myAddrBook));

  makeUserInfo((void *)&myAddrBook, "user3", 33, 1, "playing soccer");
  write(fd, (void *)&myAddrBook, sizeof(myAddrBook));

  close(fd);
  return 0;
}

# cc addr_make.c

// addr_read.c //
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <stdio.h>

struct userInfo
{
char name[28];
int age;
int sex;
char hobby[28];
};

int main()
{
int fd;
struct userInfo myAddrBook;
int dataSize;
fd = open("hello.txt", O_RDONLY);
if(fd<0)
{
perror("file open error");
return 1;
}
dataSize = sizeof(myAddrBook);
printf("User Info=================================\n\n");
while(read(fd, (void*)&myAddrBook, dataSize) == dataSize)
{
printf("name : %s\n", myAddrBook.name);
printf("name : %d\n", myAddrBook.age);
printf("name : %d\n", myAddrBook.sex);
printf("name : %s\n", myAddrBook.hobby);
printf("======================================\n");
}
close(fd);
return 0;
}
# cc addr_read.c 
# ./a.out 
User Info=================================

name : user1
name : 19
name : 0
name : programming
======================================
name : user2
name : 22
name : 1
name : playing games
======================================
name : user3
name : 33
name : 1
name : playing soccer
======================================



*파일 탐색

off_t lseek(int fd, off_t pos, int origin);


origin 값 : SEEK_CUR : pos가 0 -> 현재위치값 else -> 현 위치값 + pos

   SEEK_END : pos가 0 -> 파일의 끝지점 else-> 끝 위치값 + pos

   SEEK_SET : post 가 0 -> 파일의 시작지점 else -> 시작 위치값 + pos


// lseek.c //

int main(int argc, char **argv)

{

int fd;

int i, buf;

fd = open("num.dat", O_RDWR|O_CREAT);

if (fd < 0)

{

perror("error : ");

exit(0);

}

for (i = 1000; i < 1010; i++)

write(fd, (void *)&i, sizeof(i));


lseek(fd, 0, SEEK_SET);

read(fd, (void *)&buf, sizeof(i));

printf("%d\n", buf);


lseek(fd, 4*sizeof(i), SEEK_SET);

read(fd, (void *)&buf, sizeof(i));

printf("%d\n", buf);


}


# cc lseek.c 

# ./a.out 

1000

1004


+ Recent posts