반응형

https://www.acmicpc.net/problem/7575

 

7575번: 바이러스

첫 번째 줄에는 감염된 프로그램의 개수 N 과 바이러스 코드 추정을 위한 최소 길이를 나타내는 정수 K 가 주어진다. 단, 2 ≤ N ≤ 100이고, 4 ≤ K ≤ 1,000이다. 두 번째 줄부터 각 프로그램에 대한

www.acmicpc.net

#include <bits/stdc++.h>

using namespace std;

vector<int> getFail(const vector<int> &pattern) {
    int n = pattern.size();
    vector<int> fail(n);
    int j = 0;
    for (int i = 1; i < n; i++) {
        while (j > 0 && pattern[i] != pattern[j]) {
            j = fail[j - 1];
        }
        if (pattern[i] == pattern[j]) {
            fail[i] = ++j;
        }
    }
    return fail;
}

bool KMP(const vector<int> &pattern, const vector<int> &text) {
    vector<int> fail = getFail(pattern);
    int n = text.size();

    int j = 0;
    for (int i = 0; i < n; i++) {
        while (j > 0 && text[i] != pattern[j]) {
            j = fail[j - 1];
        }
        if (text[i] == pattern[j]) {
            if (j == pattern.size() - 1) {
                return true;
            } else {
                j++;
            }
        }
    }

    return false;
}


int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);

    int n, k;
    cin >> n >> k;

    vector<int> code[n];
    for (int i = 0; i < n; i++) {
        int m;
        cin >> m;
        vector<int> v(m);
        for (int j = 0; j < m; j++) {
            cin >> v[j];
        }
        code[i] = v;
    }

    // pattern
    for (int i = 0; i < code[0].size() - k + 1; i++) {
        vector<int> pattern(k);
        for (int j = 0; j < k; j++) {
            pattern[j] = code[0][i + j];
        }

        vector<bool> check(n);
        for (int j = 1; j < n; j++) {
            check[j] = KMP(pattern, code[j]);
        }

        // reverse
        for (int j = 1; j < n; j++) {
            if (check[j]) continue;
            reverse(code[j].begin(), code[j].end());
            check[j] = KMP(pattern, code[j]);
        }

        bool ans = true;

        for (int j = 1; j < n; j++) {
            if (!check[j]) {
                ans = false;
                break;
            }
        }

        if (ans) {
            cout << "YES\n";
            return 0;
        }
    }

    cout << "NO\n";

    return 0;
}
반응형

https://www.acmicpc.net/problem/13711

 

13711번: LCS 4

LCS(Longest Common Subsequence, 최장 공통 부분 수열)문제는 두 수열이 주어졌을 때, 모두의 부분 수열이 되는 수열 중 가장 긴 것을 찾는 문제이다. 예를 들어, [1, 2, 3]과 [1, 3, 2]의 LCS는 [1, 2] 또는 [1, 3]

www.acmicpc.net

1. 문제설명

1부터 N까지 정수가 모두 한 번씩 등장하는 두 수열 A와 B가 주어졌을 때, 두 수열의 LCS 크기를 구하는 프로그램을 작성하시오.

 

이 문제는 두 수열의 LCS 크기를 구하는 문제이다.

단 조건으로 두 수열은 모두 1부터 N 사이의 숫자로 이루어져 있음을 준다.

 

문제에서 주어진 N이 10만이므로 O(N^2) 알고리즘인 LCS 알고리즘을 이용하면

시간초과로 틀린다.

 

문제에서 주어진 조건 두 수열은 모두 1부터 N 사이의 숫자로 이루어져있음을 활용하면

이 문제를 LIS 알고리즘으로 해결할 수 있다.

 

LIS는 수열이 주어졌을 때 수열 내 가장 긴 증가하는 부분을 구하는 알고리즘이다.

LIS 알고리즘은 이진탐색을 활용하면 O(NlogN)의 시간복잡도로 문제를 해결할 수 있다.

 

단 이 문제를 LIS로 해결하는 것을 생각해내기가 조금 어렵다.

 

 

예를 들어 두 수열 A, B가 다음과 같다고 가정하자

A : 4 5 6 1 2 3

B : 3 5 1 6 2 4

 

이 경우에 LCS 알고리즘으로 테이블을 그리면 답은 다음과 같다.

 

LCS

정답은 여러가지가 존재할 수 있지만

LCS의 길이는 3이 나온다.

 

A와 B는 둘다 1부터 N의 숫자로 이루어져있다.

LCS는 공통 부분 문자열을 구하는 것이므로

A와 B의 숫자를 같은 것 끼리 동일하게 변환을 해도 동일하게 공통 부분 문자열을 구할 수 있다.

 

좀 더 쉽게 예시를 들면

A : 4 5 6 1 2 3

B : 3 5 1 6 2 4

 

다음과 같이 변환해도 동일한 길이의 공통 부분 문자열을 바꿀 수 있다.

A,B에서 같은 원소를 동일하게 변환했기 때문이다.

위와 아래는 숫자는 다르지만 LCS의 길이를 구하는 데 있어서 동일한 상태라 볼 수 있다.

 

A : 1 2 3 4 5 6

B : 6 2 4 3 5 1

 

4->1

5->2

6->3

1->4

2->5

3->6

(A에 존재한 원소를 기준으로 변환한 것이다.)

 

이렇게 되면 이제 B에서 LIS를 구해주면 

LIS중 하나로

6 2 4 3 5 1

가 나오게 되고 길이는 3이 된다.

 

 

즉 1부터 N까지의 범위를 갖는 두 수열의 LCS 길이를 구하기 위해

수열을 변환하고 LIS 길이를 구하면 답을 구할 수 있다.

 

 


2. 문제풀이코드

#include <bits/stdc++.h>

#define MX 100003
using namespace std;

int n;
int A[MX], B[MX];
int changeNum[MX];
vector<int> ans;

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);

    cin >> n;
    for(int i=1; i<=n; i++){
        cin >> A[i];
    }
    for(int i=1; i<=n; i++){
        cin >> B[i];
    }

    //숫자 변환
    for(int i=1; i<=n; i++){
        changeNum[A[i]] = i;
    }
    for(int i=1; i<=n; i++){
        B[i] = changeNum[B[i]];
    }

    //Lis
    for(int i=1; i<=n; i++){
        int idx = lower_bound(ans.begin(), ans.end(), B[i]) - ans.begin();
        if(idx == ans.size()){
            ans.push_back(B[i]);
        }else{
            ans[idx] = B[i];
        }
    }

    cout << ans.size() << '\n';
    return 0;
}
반응형

https://www.acmicpc.net/problem/14003

 

14003번: 가장 긴 증가하는 부분 수열 5

첫째 줄에 수열 A의 크기 N (1 ≤ N ≤ 1,000,000)이 주어진다. 둘째 줄에는 수열 A를 이루고 있는 Ai가 주어진다. (-1,000,000,000 ≤ Ai ≤ 1,000,000,000)

www.acmicpc.net

 

 

#include <bits/stdc++.h>

#define MX 1'000'003
using namespace std;


int n;
vector<int> v, ans, forPrint;
int arr[MX], indexArr[MX];

int lower_bound(int val) {
    int st = 0;
    int en = ans.size() - 1;

    while (st <= en) {
        int mid = (st + en) / 2;
        if (ans[mid] >= val) {
            en = mid - 1;
        } else {
            st = mid + 1;
        }
    }
    return st;
}

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);

    cin >> n;
    for (int i = 0; i < n; i++) {
        cin >> arr[i];

        int idx = lower_bound(arr[i]);
        if (idx == ans.size()) {
            ans.push_back(arr[i]);
        } else {
            ans[idx] = arr[i];
        }

        indexArr[i] = idx;
    }

    int answer = ans.size();
    cout << answer << '\n';

    for (int i = n - 1; i >= 0; i--) {
        if (indexArr[i] == answer - 1) {
            forPrint.push_back(arr[i]);
            answer--;
        }
    }

    for (int i = forPrint.size() - 1; i >= 0; i--) {
        cout << forPrint[i] << ' ';
    }

    return 0;
}
반응형

https://www.acmicpc.net/problem/11049

 

11049번: 행렬 곱셈 순서

첫째 줄에 입력으로 주어진 행렬을 곱하는데 필요한 곱셈 연산의 최솟값을 출력한다. 정답은 231-1 보다 작거나 같은 자연수이다. 또한, 최악의 순서로 연산해도 연산 횟수가 231-1보다 작거나 같

www.acmicpc.net

#include <iostream>
#include <climits>

using namespace std;

int N;
int d[503];
int matrix[503][2];
long long dp[503][503];

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);

    cin >> N;

    for (int i = 1; i <= N; i++) {
        cin >> matrix[i][0] >> matrix[i][1];
        d[i] = matrix[i][1];
    }

    d[0] = matrix[1][0];
    for (int diagonal = 1; diagonal <= N - 1; diagonal++) {
        for (int i = 1; i <= N - diagonal; i++) {
            int j = i + diagonal;
            dp[i][j] = INT_MAX;
            for (int k = i; k <= j - 1; k++) {
                dp[i][j] = min(dp[i][j], dp[i][k] + dp[k + 1][j] + d[i - 1] * d[j] * d[k]);
            }
        }
    }

    cout << dp[1][N] << '\n';
    return 0;
}
반응형

https://www.acmicpc.net/problem/11585

 

11585번: 속타는 저녁 메뉴

수원이와 친구들은 저녁 메뉴를 잘 선택하지 못한다. 배가 고픈 수원이가 보다 못해 메뉴를 정하곤 하는데 이마저도 반대에 부딪히는 경우에는 수원이가 원형 룰렛을 돌려 결정하곤 한다. 이 원

www.acmicpc.net

 

#include <iostream>

using namespace std;

#define MX 1'000'003

int N;
char arr1[2 * MX], arr2[MX];

int fail[MX];

int gcd(int a, int b) {
    if (b == 0)
        return a;
    return gcd(b, a % b);
}

void getFail() {
    int j = 0;
    for (int i = 1; i < N; i++) {
        while (j > 0 && arr2[i] != arr2[j]) {
            j = fail[j - 1];
        }
        if (arr2[i] == arr2[j]) {
            fail[i] = ++j;
        }
    }
}

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);


    cin >> N;
    for (int i = 0; i < N; i++) {
        cin >> arr1[i];
        arr1[i + N] = arr1[i];
    }

    for (int i = 0; i < N; i++) {
        cin >> arr2[i];
    }


    getFail();

    int cnt = 0;
    int j = 0;
    for (int i = 0; i < 2 * N; i++) {
        while (j > 0 && arr1[i] != arr2[j]) {
            j = fail[j - 1];
        }

        if (arr1[i] == arr2[j]) {
            if (j == N - 1) {
                if (i - j < N)cnt++;

                j = fail[j];
            } else {
                j++;
            }
        }
    }

    int _gcd = gcd(N, cnt);
    cout << cnt / _gcd << '/' << N / _gcd << '\n';
}
반응형

https://www.acmicpc.net/problem/1701

 

1701번: Cubeditor

Cubelover는 프로그래밍 언어 Whitespace의 코딩을 도와주는 언어인 Cubelang을 만들었다. Cubelang을 이용해 코딩을 하다보니, 점점 이 언어에 맞는 새로운 에디터가 필요하게 되었다. 오랜 시간 고생한

www.acmicpc.net

1. 문제설명

주어진 문자열 중에 두번이상 나오는 부분 문자열의 최대 길이를 구해야한다.

 

하나의 문자열에서 두번 이상 나오는 부분 문자열은

KMP알고리즘에서 prefix와 suffix를 비교하는 fail함수를 만드는 과정에서 구할 수 있다.

 

단 이때 이 문제에서 나올 수 있는 모든 prefix의 경우를 살펴야하기 때문에

for문을 한번 돌면서 시작지점을 정하고 그때마다 kmp fail함수를 만들어서 

가장 길게 매칭되는 prefix suffix의 길이를 구해야 한다.

 

 

2. 문제풀이코드

#include <iostream>

using namespace std;

int fail[5003];

int getFail(const string &s, int start) {
    int ans = 0;

    for(int i=0; i <5003; i++){
        fail[i] = 0;
    }

    int j = 0;
    for (int i = 1; i < s.length(); i++) {
        while (j > 0 && s[i] != s[j]) {
            j = fail[j - 1];
        }

        if (s[i] == s[j]) {
            fail[i] = ++j;
            ans = max(ans, j);
        }
    }
    
    return ans;
}


int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);

    string s;
    cin >> s;

    int ans = 0;

    for (int i = 0; i < s.length(); i++) {
        ans = max(ans, getFail(s.substr(i,s.length()-i), i));
    }
    cout << ans << '\n';

}
반응형

https://www.acmicpc.net/problem/10266

 

10266번: 시계 사진들

상근이는 보통의 시계와는 다른 독특한 시계 사진 두장이 있습니다. 시계는 n개의 동일한 길이와 목적을 가진 시계 바늘들을 가지고 있습니다. 애석하게도 시계의 숫자들은 희미해져 각 시계 바

www.acmicpc.net

 

 

여러 개의 각도를 지닌 두개의 시계를 비교할 때

회전하였을 때 둘이 같아질 수 있는지 비교해야 문제를 해결할 수 있다.

 

시계의 각도가 360,000개 있기 때문에

이를 회전하면서 비교하는 방법을 찾는 것이 중요하다.

 

직접 큐를 만들어서 회전하면서 for문을 돌며 비교할 경우에는 36만 * 36만 번 연산해야 하기 때문에

문제를 해결할 수 없다.

대신 비교할 text를 두번 반복해서 두고 pattern을 그에대해 비교하면

회전을 하지 않고 회전한 효과를 얻을 수 있다.

 

 

문제풀이코드 C++

#include <iostream>

#define MAX_LEN 360'000
using namespace std;

int N;
bool text[MAX_LEN * 2], pattern[MAX_LEN];
int fail[MAX_LEN];

void getFail() {
    int j = 0;

    for (int i = 1; i < MAX_LEN; i++) {
        while (j > 0 && pattern[j] != pattern[i]) {
            j = fail[j - 1];
        }
        if (pattern[j] == pattern[i]) {
            fail[i] = ++j;
        }
    }
}


bool kmp() {
    int j = 0;
    for (int i = 0; i < 2 * MAX_LEN; i++) {
        while (j > 0 && text[i] != pattern[j]) {
            j = fail[j - 1];
        }
        if (text[i] == pattern[j]) {
            if (j == MAX_LEN - 1) {
                return true;
            } else {
                j++;
            }
        }
    }
    return false;
}

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);

    cin >> N;

    for (int i = 0; i < N; i++) {
        int tmp;
        cin >> tmp;
        text[tmp] = 1;
        text[MAX_LEN + tmp] = 1;
    }

    for (int i = 0; i < N; i++) {
        int tmp;
        cin >> tmp;
        pattern[tmp] = 1;
    }

    getFail();

    if (kmp()) {
        cout << "possible" << '\n';
    } else {
        cout << "impossible" << '\n';
    }
}
반응형

시그널

시그널이란 소프트웨어 인터럽트이다.

프로세스에 뭔가 발생했음을 알리는 간단한 메시지를 비동기적으로 보내는 것을 의미한다.

 

시그널이 발생하는 경우는 다음과 같다.

0으로 나누기처럼 프로그램에서 예외적인 상황이 일어나는 경우나

Kill 함수처럼 시그널을 보낼 수 있는 함수를 사용해서 다른 프로세스에 시그널을 보내는 경우,

사용자가 CTRL+C와 같이 인터럽트 키를 입력한 경우가 존재한다.

 

 

시그널 처리방법

시그널이 프로세스에 도달하면 프로세슨느 각 시그널에 지정된 기본 동작을 수행한다.

대부분의 기본 동작은 프로세스를 종료하는 것이다.

하지만 프로그래밍을 통해 시그널을 무시하거나,

시그널 처리를 위한 함수(핸들러)를 지정할 수 있고

블럭처리를 할 수 있다.

 

 

시그널의 종류

시그널의 종류

 

시그널 보내기

kill -9 3255

kill -[시그널번호] PID

kill은 프로세스에 시그널을 보내는 명령어이다.

3255번 프로세스에 9번 시그널(SIGKILL)을 보내면 프로세스가 강제 종료 된다.

 

 

#include <sys/types.h>
#include <signal.h>

int kill(pid_t pid, int sig);
import os
import signal
os.kill(pid, sig) # signal.SIGALRM와 같이 시그널 변수를 사용한다.


os.killpg(pgid, sig) # 프로세스 그룹에 시그널을 보낼 때 사용한다.

 

pid > 0 인 경우 pid로 지정한 프로세스에 시그널을 발송한다.

pid < -1 일 때는 프로세스 그룹 ID가 pid의 절대값인 프로세스 그룹에 속하고

시그널을 보낼 권한을 가지고 있는 모든 프로세스에 시그널을 발송한다.

 

pid == 0 인 경우

특별한 프로세스를 제외하고 프로세스 그룹ID가 시그널을 보내는 프로세스의 프로세스 그룹 ID과 같은

모든 프로세스에게 시그널을 발송한다.

 

pid == -1 인 경우

시그널을 보내는 프로세스의 유효 사용자 ID가 root가 아니라면,

특별한 프로세스를 제외하고 프로세스의 실제 사용자ID가

시그널을 보내는 프로세스의 유효 사용자ID와 같은 모든 프로세스에 시그널을 발송한다.

 

#include <unistd.h>
#include <signal.h>
#include <stdio.h>

int main() {
    printf("Before SIGCONT Signal to parent.\n");

    kill(getppid(), SIGCONT);

    printf("Before SIGQUIT Signal to me.\n");

    kill(getpid(), SIGQUIT);

    printf("After SIGQUIT Signal.\n");
    
    return 0;
}
#결과

root@ac265c3fef72:/source/signal# ./ex8_1
Before SIGCONT Signal to parent.
Before SIGQUIT Signal to me.
Quit

SIGQUIT 시그널을 보내면 코어 덤프로 종료되는 것을 알 수 있다.

 

 

 

raise 함수를 이용하면 함수를 호출한 프로세스에 시그널을 발송한다.

// c
int raise(int sig);


//python
signal.raise_signal(signal)

 

abort함수를 이용하면 함수를 호출한 프로세스에 SIGABRT 시그널을 발송한다.

SIGABRT 시그널은 프로세스를 비정상적으로 종료 시키고 코어 덤프를 생성한다.

// c
void abort(void);

// python
os.abort()

 

 

시그널 핸들러

시그널 핸들러는 시그널을 받았을 때 이를 처리하기 위해 지정된 함수이다.

프로세스를 종료하기 전에 처리할 것이 있는 경우

특정 시그널에 대해 종료하고 싶지 않을 경우 지정하거나 (empty function)

특정 시그널에 다른 일을 하고 싶은 경우 지정한다. (do something function)

 

SIGKILL, SIGSTOP을 제외한 모든 시그널을 핸들러에 지정할 수 있다.

 

// c
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);

// python
signal.signal(signalnum, handler)

 

handler는 sig로 지정한 시그널을 받았을 때 처리할 방법을 나타낸다.

사용자자 정의 시그널 핸들러 함수명을 이용한다.

SIG_IGN : 시그널을 무시하도록 지정한다.

SIG_DFL : 기본 처리 방법으로 처리하도록 지정한다.

 

실패시 SIG_ERR을 반환하고, 성공시 이전 핸들러를 반환한다.

 

signal 함수는 시스템 마다 다르게 동작하는데

system V 계열의 경우 시그널 핸들러를 한번 사용 하면 시그널 처리 방법을 기본 처리 방법(SIG_DFL)로 재설정한다.

시그널이 들어올 때마다 시그널 핸들러를 호출하려면 매번 시그널 핸들러를 재지정해야한다.

BSD 계열의 경우는 기본 처리 방법(SIG_DFL)로 재설정 하지 않고 계속 시그널 핸들러를 계속 사용하고,

리눅스 계열의 경우 커널의 signal(2) 시스템 콜은 시스템 V와 같은 방식으로 동작하고,

gcc의 glibc 2부터 signal(3) 함수는 signal(2)를 호출하지 않고 sigaction(2)를 호출해 BSD 형식으로 동작한다.

 

 

시그널 집합

시그널을 개별적으로 처리하지 않고 복수의 시그널을 처리하기 위해 도입한 개념이다.

POSIX에서 도입했다.

 

시그널 집합의 처리를 위한 구조체 sigset_t

typedef struct{
	unsigned int __sigbits[4];
} sigset_t;

시그널을 비트 마스크(128bit)로 표현한다. 각 비트가 특정 시그널과 1:1로 연결된다.

비트 값이 1이면 해당 시그널이 설정된 것이고, 0이면 시그널 설정이 안된 것이다.

 

 

시그널 처리 함수

//sigemptyset(3)을 활용하여 시그널 집합에서 모든 시그널을 0으로 설정할 수 있다.
int sigemptyset(sigset_t *set);

//시그널 집합에서 모든 시그널을 1로 설정
int sigfillset(sigset_t *set);

//시그널 집합에 시그널 설정 추가
int sigaddset(sigset_t *set, int signo);

//시그널 집합에 시그널 설정 삭제
int sigdelset(sigset_t *set, int signo);

//시그널 집합에서 시그널이 포함되어 있는지 확인
int sigismember(sigset_t *set, int signo);

 

#include <unistd.h>
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>

int main() {
    sigset_t st;

    sigemptyset(&st);

    sigaddset(&st, SIGINT);
    sigaddset(&st, SIGQUIT);

    if(sigismember(&st, SIGINT))
        printf("SIGINT is setting.\n");

	//__val은 시스템 환경마다 다른 변수 이름을 사용해야한다 ubuntu에서는 __val 사용
    printf("** Bit Pattern: %x\n", st.__val[0]);

    return 0;
}

실행 결과

SIGINT is setting.
** Bit Pattern: 6

 

sigchild로 자식 프로세스 정리

#include <unistd.h>
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>

static void sig_child(int);

int main() {
    pid_t pid;
    int i;
    signal(SIGCHLD, sig_child);

    pid = fork();
    
    //자식인 경우 pid가 0이므로 sleep후 종료한다
    if(pid == 0){
        sleep(1);
        exit(0);
    }
    while(1){
    //부모인 경우 계속 while문을 돈다.
        i = i;
        sleep(1);
    }
    return 0;
}


static void sig_child(int signo){
    pid_t pid; int status;
    
    //wait함수로 자식프로세스 종료를 기다린다.
    pid = wait(&status);
    
    printf("child %d finished\n %d", pid, status);
}

 

SIGFPE로 divide by zero 에러 처리

#include <unistd.h>
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>

static void sig_fpe(int);

int main() {
    pid_t pid;
    int i;
    signal(SIGFPE, sig_fpe);

    i = i/0;
}


static void sig_fpe(int signo){
    pid_t pid; int status;
    printf("Divide by 0 Error\n");
    
    exit(1);
}

 

 

기타 시그널 처리 함수

// 시그널 정보 출력
// s에 지정한 문자열을 붙여 정보 출력
void psignal(int sig, const char *s);

//인자로 받은 시그널을 가리키는 이름을 문자열로 리턴
char *strsignal(int sig);

//시그널 블록킹과 해제
//인자로 받은 시그널을 시그널 마스크에 추가하거나 해제한다
int sighold(int sig);
int sigrelse(int sig);

 

 

#include <unistd.h>
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>


void handler(int signo){
    char *s;
    s = strsignal(signo);
    printf(stdout, "Received Signal : %s\n", s);
}

int main() {
    if (sigset(SIGINT, handler) == SIG_ERR){
        perror("sigset");
        exit(1);
    }

    sighold(SIGINT);
    pause();

    return 0;
}

이 경우 CTRL+C로 SIGINT를 보내도 프로그램이 종료되지 않는다.

 

 

//시그널 집합 블록과 해제
int sigprocmask(int how, const sigset_t *restrict set, sigset_t *restrict oset);

how : 시그널을 블록할 것인지, 해제할 것인지 여부 결정 

SIG_BLOCK : set에 지정한 시그널 집합을 시그널 마스크에 추가

SIG_UNBLOCK : set에 지정한 시그널 집합을 시그널 마스크에서 제거

SIG_SETMASK : set에 지정한 시그널 집합으로 현재 시그널 마스크를 대체

 

set은 블록하거나 해제할 시그널 집합 주소를 의미하고, oset은 NULL 또는 이전 설정값을 저장한 시그널 집합 주소이다.

 

#include <unistd.h>
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>


int main() {
    sigset_t new;

    sigemptyset(&new);
    //시그널 집합에 SIGINT, SIGQUIT 설정
    sigaddset(&new, SIGINT);
    sigaddset(&new, SIGQUIT);
    sigprocmask(SIG_BLOCK, &new, (sigset_t *) NULL);

    printf("Blocking Signals : SIGINT, SIGQUIT\n");
    printf("Send SIGQUIT\n");
    //SIGQUIT 시그널 보내기
    kill(getpid(), SIGQUIT);


    sleep(5);
    printf("UnBlocking Signals\n");

    //시그널 집합 블록 해제
    sigprocmask(SIG_UNBLOCK, &new, (sigset_t *) NULL);

    return 0;
}

위 코드처럼 시그널을 블록해두면 해당 시그널을 처리하지 않고 대기상태로 두었다가,

시그널 집합 블록을 해제하면 그때 대기해두었던 시그널들을 처리한다.

 

 

시그널 대기 함수

// 시그널 대기
//sig : 시그널이 올 때까지 대기할 시그널(1개)
int sigpause(int sig);

//set: 기다리려는 시그널을 지정한 시그널 집합
int sigsuspend(const sigset_t *set);

 

 

sigset(집합)과 sigsuspend 사용으로 시그널을 기다릴 수 있다.

#include <unistd.h>
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>

void handler(int signo){
    psignal(signo, "Received Signal:");
}


int main() {
    sigset_t set;
    sigset(SIGQUIT, handler);

    sigfillset(&set);
    sigdelset(&set, SIGQUIT);

    printf("Wait...\n");

    sigsuspend(&set);


    return 0;
}
Wait...
^Z^X^C
^C
^C
^\Received Signal:: Quit

 

 

//시그널 기다리기
int sigwait(const sigset_t *set, int *sig)

set에 포함된 시그널만 기다리고, 다른 시그널은 블럭되지 않는다.

sig에는 시그널을 수신하였을 때, 수신한 시그널 번호를 저장한다.

 

#include <unistd.h>
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>

void handler(int signo){
    psignal(signo, "Received Signal:");
}

int main() {
    sigset_t set;
    int sig;
    sigset(SIGQUIT, handler);

    sigfillset(&set);
    sigdelset(&set, SIGQUIT);

    printf("Wait...\n");

    //시그널이 올때까지 가디렸다가 다 처리한다.
    sigwait(&set, &sig);

    psignal(sig, "Continued by signal :");
    fflush(stdout);

    return 0;
}

 

시그널 보내기 sigsend

int sigsend(idtype_t idtype, id_t id, int sig);

idtype은 id에 지정한 값의 종류, id는 시그널을 받을 프로세스나 프로세스 그룹, sig는 보내려는 시그널을 의미한다.

 

sigsend idtype

시그널 무시처리 sigignore

int sigignore(int sig);

인자로 지정한 시그널의 처리방법을 SIG_IGN으로 설정한다.

 

 

 

 

SIGNAL 함수 호환성

svr4 시스템과 BSD 시스템 간의 동작이 다르다.

앞으로 개발할 때는 이식성을 고려하여 signal을 사용하지 말고 sigaction을 사용한다.

 

 

시그널과 프로그램 시작

프로세스가 fork될 때

자식 프로세스는 부모 프로세스의 시그널 처리를 상속한다.

 

프로그램이 exec될 때는

기본 동작이 정의된 모든 시그널은 기본 동작으로 변경하고,

기본 동작이 없는 시그널은 그대로 둔다.

 

대화형 쉘(Interactive Shell)에서 실행하는 경우

백그라운드 프로세스는 인터럽트 및 종료 신호의 처리를 무시하도록 설정하고

많은 대화형 프로그램은

백그라운드에 있지 않을 때만 신호를 포착한다.

int sig_int(), sig_quit()

if(signal(SIGINT, SIG_IGN) != SIG_IGN) signal(SIGINT, sig_int);
if(signal(SIGQUIT, SIG_IGN) != SIG_IGN) signal(SIGQUIT, sig_quit);

 

+ Recent posts