본문 바로가기

컴퓨터/언어,프로그래밍

프로세스

프로세스C/C++ 2009/03/10 17:00

프로세스
 * 실행중인 프로그램을 말한다. 

ps -aux 를 통해 현재 실행중인 프로세스를 볼수 있다. 


init 프로세스
모든 프로세스는 pid를 가지고, 또한 ppid를가진다.  pid 가 1인 프로세스가 init 프로세스다.
init 프로세스는 사용자들을 위해서 시스템을 설정하게 된다. 
모든 프로세스는 init으로 부터 fork & exec 과정을 거쳐 독립된 프로세스로 임무를 수행하게 된다. 

 * init 프로세스가 하는일
   * 파일 시스템의 구조 검사
   * 파일 시스템의 마운트
   * 서버 데몬을 띄운다. 
   * 사용자로긴을 기다린다. 
   * 사용자가 로긴하면 사용자를 위한 쉘을 띄운다. 

 * init 이 처음 시작해서 수행해야할 작업들을 설정한 파일은 /etc/inittab 파일이다. 
   init은 새로운 실행레벨에 실행할 프로세스를 결정하기 위해서 이 파일을 참조한다.  
 * inittab 파일은 시스템의 상태에 따라서 해당하는 런레벨에서 init프로세스가 수행해야 할 일들을 서술해 놓은 파일이다.
 * init프로세스는 inittab 파일을 참조해서 모든 새로운 런레벨에서 실행할수 없는 프로세스가 만약 지금 실행중이면 그 프로세스를 죽이고, 
   새로운 런 레벨에서 실행해야만 하는 프로세스중 현재 실행되고 있지 앟은 프로세스는 새로이 실행을 시킨다. 
 * 부팅이 정상적으로 가동이되면 init 사용자들은  로그아웃한 터미널에 다른 사용자들이 다시 로긴 할수 있도록 getty를 재실행 시킨다. 
   또한 init은 고아 프로세스들을 거두어 양자로삼는다. 
 * init 자신은 죽음이 허락되지 않는다. 심지어 init에 SIGKILL 시그널을 보낸다 하더라도 그것을 죽일수 없다. 

etc/inittab 파일

 id:runlevels:action:process 

위와 같이 네 부분으로 나뉘어 진다. 

 * id        - 해당라인을 다른부분과 식별시켜준다. getty를 설정하는 부분에서는 이곳에 터미널 번호를 지정해주도록 되어있다. 
               getty 설정부분이 아닌 곳에서는 이렇지 않다. id는 길이제한이 있고, 파일내에 유일한 것이어야 한다. 
 * runlevels - 이것은 해당라인이 어떤 실행레벨에서 유효한지를 지정하는 부분이다. 실행레벨은 한자리 숫자로 표현되며
               특별한 구분기호 없이 연속적으로 여러 실행 레벨을 써 넣을수 있다.
 * action    - 여기서는 해당라인이 어떻게 동작해야 하는지를 지정한다. respawn 이라고 쓰게되면, 그다음 영역에 있는 명령이
               종료될때마다 그것을 재실행 하게 된다. once라고 쓰게되면 실행을 딱한번만 하게 된다. 
 * process   - 이곳에 실행시킬 명령이 들어간다.


예) 일반적인 다중사용자가 실행레벨(multi-user run level, 2번부터 5번까지)에서 getty를 첫번째 가상 터미널에 띄우고 싶다면,
    다음과 같이 해야한다. 

1:2345:respawn:/sbin/getty 9600 tty1 

첫번째 부분(1)은 이라인이 /dev/tty1을 위한것이란점을 알려준다. 
두번째 부분(2345)은 이것이 실행레벨 2,3,4,5번에 적용되도록 지정한것
세번째 부분(respawn)은 명령의 실행이 종료될때마다 다시 실행되도록 하는부분(즉 다시 로그아웃 했다가 다시 로그인, 로그아웃할수있도록..)
마지막 부분(/sbin/getty 9600 tty1)은 명령으로서 , 첫번째 가상터미널에 getty를 띄우라고 지시하고 있다. 

 
예제...
1:2345:respawn:/sbin/getty 38400 tty1
2:23:respawn:/sbin/getty 38400 tty2
3:23:respawn:/sbin/getty 38400 tty3
4:23:respawn:/sbin/getty 38400 tty4
5:23:respawn:/sbin/getty 38400 tty5
6:23:respawn:/sbin/getty 38400 tty6

어떤 명령이 실행에 실패한다면, init은 그것을 다시 재실행하게 된다. 그러나 재실행하고 실패하고, 다시 재실행하고, 실패하고.. 

 * 실행레벨
   init은 시스템이 제공할 여러서비스들을 실행시키는데, 이것을 어떤 수준으로 실행시킬지 등급을 나눠정의한것이 실행레벨이란 개념이다.
   실행레벨은 숫자로 나타내어진다. 

   0 : 시스템 종료
   1 : 단일 사용자모드(특별한 시스템 관리 작업용)
   2-5 : 일반적인 시스템 가동상태(사용자 정의가능)
   6 : 리부팅

참고) 단일 사용자 모드 : 단지 관리자만이 시스템을 사용할수있다. login같이 시스템 가동에 필수적인 최소한의 서비스만이 실행됨..
                       단일 사용자모드는 몇몇 시스템관리 작업을 하기 위해서 필요하다.. 
                       예를 들면 /usr 파티션에 fsck를 실행키시는 일... fsck를 실행시키기 위해서는 해당파티션을 언마운트시켜야
                       하는데.. /usr 같은 파티션을 언마운트시키려먼 거의 모든 시스템 서비스들을 종료시켜야 한다. 

 * 로긴은 어떻게 이루어지는가...
   init은 getty 프로그램을 각각의 터미널(혹은 콘솔)에 실행시킨다.. 
   getty는 터미널에서 로그인 하려는 사용자가 있는지..살펴보면서 기다린다..
   (즉 사용자가 뭔가를 타이핑 하지 않은지 살펴본다..) 
   사용자가 있다면, getty는 환영메시지를 출력하고 login 프로그램을 실행시킨다. 
   login프로그램은 usename을 매개변수로 전달을 받고, 해당password를 묻기 위해 프롬프트를 띄운다. 
   password가 정확하면, login은 설정되어있는 쉘을 실행시킨다. 
   password가 틀리면 login 은 몇번더물어보고 종료된다. init은 login프로그램이 종료된것을 감지하고, 터미널에 새로운 getty를 띄워놓는다.

 * 새로운 프로세스는 오직 init에 의해서만 생긴다..(fork시스템 호출을 사용한다. ) 
   getty와 login은 단지 실행중인 프로그램과 교대를 할 뿐이다. (exec시스템 호출을 사용해서..)

데몬 프로세스
 * 터미널 세션에 속하지 않고 배경으로 돌고있는 프로세스.
  (많은 시스템 서비스들은 데몬으로 돌고있다 -ex) 네트웤서비스/프린팅서비스..)
 * 터미널을 가지지 않는다. (백그라운드 프로그램은 터미널을 가지지만..)
 * 특별한 일이 없는한 사용자와 상호대화할 필요없이 아무도 모르게 실행된다.
 * 모든 데몬프로그램은 PPID가 1로 세팅. -> 데몬프로그램의 관리는 init이 담당한다. 
 * SID 는 PID 와 같다. 
 * 다시 제어 터미널을 얻지 못해야 한다. 그걸 만족하기 위해서 setpgrp를 호출하여 제어터미널을 날리고 프로세스의 그룹리더가 된다.. 
   그런데 프로세스 그룹리더이면 제어터미널을 어떤 방식으로든 얻을수 있는 경우가 있다.
   그래서 그룹 리더임을 포기하기 위해서 fork해서 생기는 child를 데몬으로 만든다....(System V에서만..)
   BSD에선 두번 fork하지 않아도 프로세스 그룹ID가 0이 아닌 프로세스 그룹리더인 경우엔 제어터미널을 다시 할당받지 못하도록 하기 때문에 fork 가 필요가 없다...

데몬 프로그램을 만드는 방법
1. 우선 fork를 호출해서 자식프로세스를 생성시킨다음 부모프로세스를 종료시킨다.
   ( 자식 프로세스가 종료하기 전에 부모프로세스가 종료되다면, 이때의 자식프로세스의 관리는 자동적으로 init이 담당하게 된다. )

2. setsid를 이용하여 세로운 세션을 만든다. 그리고 현재프로세스(자식)의 PID가 세션의 제어권을 갖도록 한다.
   (setsid는 새로운 세션을 생성하기 위해서 사용한다. 보통의 세션은 자신의 세션을 위한 TTY를 가지는데, 새로운 세션을 생성하면
   여기에 TTY를 부여해주어야 한다. 그렇지 않으면 터미널을 가지지 않는 세션을 갖게된다. )

3. chdir을 이용하여 프로세스가 루트디렉토리에서 작업을 수행하도록 변경시킨다. 
   (선택사항이다. 데몬프로그램에서 여러가지 파일을 읽고 쓰는 작업을 할때 상대경로를 명시함으로써 일어나는 혼동을 막기위해권장) 

좀비 프로세스
 * 유닉스 상에서 defunct 라고 불리는 좀비는 시스템상에 많이 생기면 쓸데없는 자원낭비로 시스템의 성능이 저하가 된다. 
   좀비들은 init 프로세스에 종속되어 제거될때까지 시스템에 남게된다. 

 * 좀비가 생성되는 조건
   1. 부모프로세스가 정상적으로 종료하지 않거나, wait를 수행되지 않고 있는 상태에서 자식이 퇴장할때.
   2. 하나 이상의 자식 프로세스가 수행되고 있는 상태에서 부모가 퇴장할때..

프로세스 제어
fork 와 exec
 * fork 와 exec 는 둘다 유닉스 시스템에서 새로운 프로세스를 생성시키기 위해서 사용하는 System Call 함수. 
 * fork 
   * 호출한 프로세스와 똑같은 프로세스를 copy-on-write 형식으로 실행하게 된다.
   * 생성된 프로세스는 자신만의 PID를 가지고 독자적인 길을 가게 된다. 
   * fork 되어서 만들어진 프로세스를 자식 프로세스라고 하고, fork()를 호출한 프로세스를 부모 프로세스라 한다. 
   * 프로세스의 복사본을 만들때 사용한다.
   * 다수의 클라이언트 연결을 처리해야 하는 네트웍서버 를 제작할때 매우 흔히 사용된다.
   * 리턴값은 int형 정수다.. 0일경우 자식프로세스를, 0보다 큰정수일경우 부모프로세스를 나타낸다. fork 실패시 -1을 리턴한다. 
 * exec
   * exec 는 흔히 exec 계열함수군에 의해서 구현되며, exec 함수군에는 execl(3), execlp, execle.. 등이 있다. 
   * 모두 같은 일을 하며, 단지 프로그램실행 아규먼트를 다루는데 약간씩의 차이를 가지고 있을 뿐이다.
   * exec 역시 fork 와 마찬가지로 새로운 프로새스를 생성시킨다. 
   * fork 와 같이 copy-on-write 를 이용한 전혀 새로운 프로세스를 실행시키지 않고, 현재의 프로세스이미지를 새로운 프로세스 이미지가 덮어 써 버린다.

 * init 프로세스를 fork/exec 방식으로 새로운 프로세스 생성하는 방법
   init 프로세스에게 어떤 프로세스를 실행시켜라는 메시지가 전달되면, 
   init 는 fork 를 이용해서 자기자신을 복사한 자식 프로세스를 하나 실행시키게 될것이다. 
   그리고 나서 복사된 자식프로세스에서 exec 를 써서 새로운 프로세스를 실행시키면 init 는 새로운 프로세스로 대체실행되는 것이다.

  new_process 를 실행하라
     |
     V
 +---------+ fork  +---------+ exec(new_process)   +-------------+
 | init(1) |----->>| init(?) |-------------------->| new_process |
 +---------+       +---------+                     +-------------+


참고) system(3) 이라는 새로운 프로세스를 시키는 함수도 있는데, fork & exec 의 다른 구현으로 보면 될것이며, 실제로 system 을 사용하지 않고, 
  fork & exec 를 통하여 구현하는 경우도 있다. 

vfork()
 * fork()는 부모프로세스의 전체를 자식프로세스를 위해 복사하기 때문에 많은 자원의비용이 든다.. 이에 vfork()가 개발됨.
 * 부모와 자식사이의 수행순서를 보장한다. 
 * fork()와는 달리 부모프로세스의 주소공간을 공유한다. 
  자식프로세스가 부모프로세스의 메모리 공간에서 실해오디고 있는동안 부모 프로세스는 실행되지 않는다. 
  부모프로세스는 vfork()함수를 호출하여 자식프로세스를 생성하고 멈춰있다가 자식프로세스가 exit(), _exit()함수를 호출하고 종료되면
  그때 실행을 재개한다. -> 이렇게 함으로 자식프로세스가 좀비가 되는것을 막을수 있다. 
 * vfork()에 의한 자식프로세스 생성은 부모프로세스의 변수의 예기치 못한 변경을 피하기 위해 아주 주의깊게 사용되어야 한다. 
  자식 프로세스는 vfork()를 포함하는 함수로부터 return이 없어야 하고, exit()를 호출하지 말아야 한다
  (만약 exit가 필요하다면 _exit()를 사용해야 한다. -이유는 아래서 설명..)
 * vfork() 와는 관련해서 많은 문제가 있다. 프로그램에서 vfork()를 사용하지 않는것이 좋다. 참조사이트 참고 ㅡㅡ;
  http://wiki.kldp.org/HOWTO//html/Secure-Programs-HOWTO/avoid-vfork.html

=== exit() / _exit()
exit()와 _exit()는 약간의 차이가 있다. 특히 fork()를 사용하느냐, vfork()를 사용하느냐에 따라 중요성이 더한다..
exit()와 _exit()의 기본적인 차이는 exit()는 사용자 모드의 clean-up 을 수행하며, 사용자에게 지원되는 함수형태이고, 
                                   _exit()는 커널모드에서 동작한다.

fork()의 자식 프로세스에서 exit()를 사용하는것은 일반적으로 틀리다. 
왜냐하면 이것을 사용하면 stdio 버퍼가 두번 flush 되도록하고 임시 파일들이 예기치 못하게 삭제가 된다. 
(일반적인 경우는 아니지만, 데몬 프로그램의 경우에 자식 프로세스에서 보다는 부모프로세스에서 _exit()가 사용되어야 한다. 
기본룰은 exit()는 main()함수 내에서 한번만 수행되어야 하는것이다. )

vfork()에 의한 자식 프로세스에서 exit()의 사용은 부모프로세스의 상태를 변경시킬수 있기 때문에 아주 위험하다.

wait()/waitpid()
 * wait()
 fork()를 이용해서 자식 프로세스를 생성했을때에 사용한다. wait()를 쓰면 자식프로세스가 종료할때까지 해당영역에서 
 부모프로세스가 sleep모드로 기다리게 된다. 이는 자식 프로세스와 부모프로세스의 동기화를 위한 목적으로 부모프로세스가 자식 프로세스보다
 먼저 종료되어 자식 프로세스가 고아프로세스가 되는거 모든시스템 자원을 해제한다. 
 * waitpid()
 인수로 주어진 pid버놓의 자식프로세스가 종료되거나, 시그널 함수를 호출하는 신호가 전달될때까지 waitpid 호출한 영역에서 일시중지된다.
 pid로 지정된 자식이 waitpid함수 호출전에 이미 종료되었으면 함수는 즉시 리턴하고, 자식 프로세스는 좀비프로세스 로 남는다. 

  pid < -1 : 프로세스 그룹 ID가 pid의 절대값과 같은 자식의 프로세스를 기다린다. 
  pid -1 : 임의의 자식 프로세스를 기다린다. -> wait()와 동일하다. 
  pid 0 : 프로세스 그룹 ID가 호출 프로세스의 ID와 같은 자식프로세스를 기다린다. 
  pid > 0 : 프로세스 ID가 pid의 값과 같은 자식 프로세스를 기다린다.
 

프로세스 관계
process group
 * 프로세스들은 프로세스 Id이외에, 프로세스 group ID()를 갖는다.
 * getpgrp() 함수로 프로세스 그룹 ID를 얻을 수 있다.

#include <sys/types.h>
#include <unistd.h>
pid_t getpgrp(void);
return : 호출한 프로세스의 그룹 ID


 * 프로세스 그룹의 특징
   * 프로세스의 집단으로 signal전달등을 위해서 설정됨
   * fork()시 부모의 process group ID 를 상속받는다. 
   * 각 프로세스 그룹에는 process group leader가 있다.
   * process group leader의 process ID가 process group ID가 된다.
   * 각 process group leader는 process group을 만들고 그 group안에 프로세스를 생성하고 종료할 수 있다.
   * group안에 프로세스가 하나라도 있으면 group leader가 종료하던지에 상관없이 그 프로세스 group은 존재한다.
   * process group안에 남아있는 마지막 프로세스는 그 process group을 종료하던지 아니면 다른 process group으로 이동할수 있다.
   * 한 프로세스는 기존의 프로세스 그룹에 join 하거나, setpgid함수를 호출하여 새로운 프로세스 group을 만들 수 있다.
 
예) kill -INT -3245 명령은 프로세스 그룹 3245에 SIGINT보낸다. 
    (cf. kill -INT 3245는 프로세스 3245에만 보낸다. )

#include <sys/types.h>
#include <unistd.h>
int setpgid (pid_t pid, pid_t pgid) 

 * setpgid 함수는 프로세스 그룹 pgid에 프로세스 pid를 소속시킨다. 
 * 두 인자가 같은 경우, 호출한 프로세스는 pid가 process group leader가 된다.
 * pid가 0이면 caller의 프로세스 ID를 이용한다. 
 * pgid가 0이면 process ID가 process group ID가 된다.
 * 리턴값 : 성공하면 0을 리턴, 실패하면 -1 리턴   
 * 에러 
   * EACCES : pid라는 이름을 가진 자식 프로세스가 만들어진 후에 exec 함수를 통해서 실행되었다.
   * EINVAL : pgid의 값이 유용하지 않다.
   * ENOSYS : 시스템이 작업제어를 지원하지 않는다.
   * EPERM  : pid 인수에 의해 지적된 프로세스가 세션리더이거나, 호출한 프로세스와 같은 세션에 없거나, 
              pgid 인수의 값이 호출한 프로세스와 같은 세션안에 있는 프로세스 그룹 ID와 매치되는 것이 없다. 
   * ESRCH  : pid 인수에 의해 지적된 프로세스가 호출한 프로세스가 아니거나 호출한 프로세스의 자식 프로세스가 아니다.  

- 대부분 job control에서 fork를 한후에 이 함수를 호출하여 부모가 자식의 프로세스 group ID를 세팅하거나 
  자식이 자신의 프로세스 그룹 ID를 세팅하기 위해서 하나의 프로세스는 자신의 프로세스 그륩 ID나 자식의 프로세스 그룹 ID를 
  set할 수 있으나 자식이 exec를 했을 경우는 불가능하다. 
  하나의 프로세스 그륩에 signal을 보낼 수도 있으면 waitpid를 호출할 때 프로세스 그룹안에서 특정한 프로세스를 기다리게 할 수도 있다.

session
 * session이라는 것은 여러개의 프로세스 group들을 모아 놓은 것을 session이라고 한다.
 * job(프로세스 그룹)제어 목적으로 설정.
 * 하나의 프로세스는 setsid함수를 호출함으로써 하나의 세션을 만든다.
 * calling하는 프로세스가 process group leader가 아닌 경우 
   * 새로운 session을 만든다.
   * 그 프로세스는 이 새로운 session의 session leader가 되고 이 새로운 세션에 이 프로세스만이 존재한다.
   * 그 프로세스는  또한 새로운 프로세스 group의 group leader가 된다.
   * 그 프로세스는  controlling terminal을 가지지 않는다
 * calling하는 프로세스가 process group leader인 경우 
   * process group leader가 setsid를 호출한 경우 에러가 발생한다.
   * 먼저 fork을 수행한후에 부모를 종료한다.
   * fork를 수행하였으므로 부모의 프로세스 group ID가 전달되지만 그러나 자식 프로세의 ID가 새롭게 만들어 지므로 
     부모로부터 전달된 process group id와 새로이 생성된 process id가 일치하지 않으므로 앞에서와 같은 
     새로운 session을 생성할 수 있다.
 * 세션은 controlling terminal을 가진다. 


#include <sys/types.h>
#include <unistd.h>
pid_t setsid (void) 

 * setsid 함수는 새로운 세션을 만든다. 
 * 호출한 프로세스는 세션리더가 된다.  
 * 호출한 프로세스의 ID와 같은 ID를 가진 새로운 프로세스 그룹이 만들어지고 호출한 프로세스가 그 안에 소속된다. 
 * 새로운 프로세스 그룹에 다른 프로세스들이 없고, 새로운 세션안에 다른 프로세스 그룹이 없이 초기화된다. 
 * 호출한 프로세스가 제어중인 터미널을 갖지 않도록 만든다. 
 * 리턴값 : 성공하면 호출한 프로세스의 새로운 프로세스 그룹 ID, 실패하면 -1   
 * 에러 
   * EPERM : 호출한 프로세스가 이미 프로세스 그룹의 리더이거나, 같은 프로세스 그룹 ID를 가진 다른 프로세스 그룹이 있다. 
             (process group leader가 setsid를 호출한 경우 에러가 발생한다.) 이때 먼저 fork을 수행한후에 부모를 종료한다.
             fork를 수행하였으므로 부모의 프로세스 group ID가 전달되지만 그러나 자식 프로세의 ID가 새롭게 만들어 지므로 
             부모로부터 전달된 process group id와 새로이 생성된 process id가 일치하지 않으므로 앞에서와 같은 새로운 session을 생성할 수  있다.

controling teminal
 * 프로세스가 생성된 로긴 터미널이다. 한그룹은 제어 터미널이 동일하다.
 * 터미널은 그 터미널의 제어그룹 소유이다. 
 * 한 프로세스가 새 그룹을 만들면 제어 터미널을 잃게된다. 후에 오픈하는 터미널이 새 제어터미널이 된다.   
 * 모든 프로세스 그룹은 서로 다른 제어 터미널을 가진다. 
 * controlling terminal에 연결을 설정한 session leader가 controlling process가 된다.
 * 하나의 세션에 있는 프로세스 그룹들은 foreground process group과 background process group으로 나누어 진다.
 * 터미널에서 발생한 signal(터미널에서 인터럽트키)은  forground process group에 있는 모든 프로세스에게 전해진다.
 * 연결설정과 관련된 signal은 controlling process(session leader)로 넘어간다.  
 * 세션이 제어터미널을 갖고 있다면 하나의 포그라운드 프로세스 그룹을 갖는다. 그리고 그 세션안의 모든 다른 프로세스 그룹은 백그라운드 프로 세스 그룹이 된다. 

 * 제어그룹 : 각 터미널은 하나의 프로세스 그룹에 연관한다. 
 이 그룹은 터미널의 제어 그룹이라 불린다. SIGINT, SIGQUIT등 시그널은 이 그룹의 모든 프로세스에 전달

job contol
 * job control은 하나의 single terminal로부터 많은 job(groups of process)을 start시키고 
   어떤 job이 terminal에 접근할 수 있는지를 통제하고 어떤 job이 background에서 수행되고 
   어떤 job이 foreground에서 수행될지를 통제하는 것을 말한다.   

 * background 처리 / foreground처리
   * 콘솔상태에서 명령을 실행시킬때 명령이 종료될때까지 그 콘솔은 사용할수 없다. 다른 콘솔로 작업을 해야 한다. 
     다른 명령어를 사용하려고 할때는 새 터미널을 하나 띄워야 하는데 이런 작업을 foreground라고 한다.
     Ctrl-C로 작업을 종료시킬수 있다. 
   * 백그라운드 작업을 실행시키면, 프롬프트는 바로 명령대기 상태로 전환한다. 이 작업은 Ctrl-C로 종료시켰을때등
     입력작업을 받지 못한다. 일단 실행을 시키고 나면, kill 명령어로 강제로 종료시키는 방법밖에 방법이 없다. 
     백그라운드로 작업을 하려면, 명령뒤에 & 문자를 입력한다. 

 * job control을 위해서는 다음과 같은 것이 제공되어야 한다. 
   * 작업 통제를 지원하는 shell
   * 커널안에 있는 job control을 지원 하는 terminal device driver.
   * 작업 통제를 위한 signal
     * DELETE or Control-C (generate SIGINT)
     * Control-backslash (SIGQUIT)
     * Control-Z (SIGTSTP)
 * 만약 background 프로세스가 terminal로부터 무언가를 읽을려고 한다면 그 프로세스에게 SIGTTIN signal를 보내고 
   이 신호는 background process를 멈추게 한다.
 * 그러나 만약 background process가 terminal에 무언가를 쓸려고 한다면 어떻게 될까 이것은 하나의 option이다.
   시스템에서 default는 쓸 수 있게 되어 있다 그러나 만일 원하지 않는다면 다음과 같이 하면 된다.

$stty tostop

만일 이렇게 setting해 놓고 background process가 terminal에 무언가를 쓸려고 한다면 그 프로세스에게 SIGTTOU 신호를 보낸다.
이 신호는 그 프로세스를 멈추게 한다.
제주삼다수, 2L,... 오뚜기 진라면 매운... 상하목장 유기농 흰... 남양 프렌치카페 카... 고려인삼유통 홍삼 ... 종근당건강 오메가3... 요이치 카링 유무선...