728x90

Linux 실습용 코드를 돌려보려고 makefile 을 쳤더니 발생한 오류

 

사실 -lsocket 은 solaris 를 위한 플래그로 나에게는 필요도없고 없는 라이브러리인데

 

샘플코드에서 삭제하지 않고 컴파일 해서 오류가 뜬 것이었다

 

저거 말고 다른 에러가 뜨는 경우 라이브러리가 설치되지 않아서 오류가 뜨는 것일수도있다....

 

그경우 yum 으로 설치헤주면 된다고한당!

728x90
728x90

팀플하느라 강제로 깃을 써본적은있는데..

 

공부한 내용들을 정리해야지 하며 미루고 미루다 오늘은 해본다...

 

찔금찔금 깃을 배우고 써봐서 뭔가 다 해보긴 한것들인데 막상 하려니 뭐부터 할지 혼란스러워서 미뤄왔기에 과정을 정리해본다.

엄청엄청 쉽게쓸생각이니까 나의 미천한 글이 처음하시는 분들에게 도움이 되길 바람

물론 첫술에 배부를 수 없으니 더 좋은 글들도 찾아보시긜....

 

 

1. GITHUB 회원가입 : 은 패스

구글 네이버 가입하는거랑 비슷허다

 

2. Repository 생성

들어가면 메인부터 만들기가 잘 보이는곳에있다..

만들기를 누르고

저장소이름 / 내용을 간단히 적으면 된다

부끄러우면 프라이빗 해도 되지만 뭐... 난 그냥 다 퍼블릭으로 했다 하하

열심히 해보고 싶은 프로젝트는 프로젝트 단위로 만들었고 

자잔한 공부는 비슷한 주제끼리 묶기로 했다(오늘 만드는 레포지토리 : 운영체제와 리눅스 시스템콜)

 

로컬에서 git init을 하고 그걸 올려도 되긴 하나 나는 repository 생성 후 clone 이 왠지 더 좋당

Add a ReadMe 나 .gitignore 는 선택하던말던 상관없는데

리드미만 추가하는걸 선호한다

.gitignore 는 아래에서 작성할거고

Readme는 개대충 깃허브가 자동으로 한두줄이라도 써주기때문에 체크하면 편하다고 갠적으로 생각(찐 프로젝트는 리드미가 엄청 중요하지만.... 일단은 올리는게 중요하니까 그건 나중에 생각하자)

 

3. git clone

로컬에서 입력하는 명령어. 방금 위에서 생성한 레포의 링크를 넣으면

깃이 들어있는..?폴더를 통째 생성해준다.

명령어는

git clone [레포지토리URL] 이다.

 

 

 

누르면 URL이 복사되고..

ssh 를 쓰고싶으면 ssh 키를 받아야하는데 그건 다음에 글을 또 써봐야겠담...

난 저번에 받아둔게 있어서 그냥 고고

일단 HTTPS해도 갠춘하다

 

terminal 로 해당 폴더를 놓을 경로에 가서

명령어를 치면 된당

(윈도우 쓰는 사람이면 깃 설치했으면 아마...폴더에서 우클릭하면 GIT Bash 라는게 있고

그거 누르면 CLI창이 뜰것이당 거기서 명령어 치면 되고,

맥의 경우는 파인더에서 맨밑에 조그맣게 경로가 나오는데 거기서 폴더 우클릭하면 Open in terminal 이 있다.

리눅스쓰는사람은....뭐 내가 설명을...할필요가있나....?ㅋㅋㅋ)

 

그러면 짜잔! .git 디렉토리가 있는 reposirtory 와 동일한 디렉토리가 만들어진당

이거 열면 .git 이랑 리드미 뭐 고런거 그대로 들어있음~

 

 

3. 소스코드 업로드 / 코딩

 나는 이미 작성해둔 코드가 있었으므로 복붙(원래 경로에는 오만게 다있어서 복잡하고... 깃허브에는 내가 다시 참고하고플것 같은거... 좀 깔끔하게 올려보려한다...)

또, 약간 레포지토리 안에서도 주제별로 나누려고 디렉토리를 하나 더 만들었다

Makefile 은 요 디렉토리 안에 작성할 것이다

 

 

 

4. .gitignore 와 Makefile 작성(패스해도 ㄱㅊ)

 

.gitignore : github에 올리지 않는 파일이나 디렉토리, 확장자를 설정한다. API key같은것도 이그노어 해주어야한다.

걍 파일명을 .gitignore로 하고 아무 에디터나 써서 내용을 적으면 된다.

메모장 ㅇㅋ

 

나는 오늘은.. 확장자 .a 와 .o 를 일단 제외해 주었다.

본인이 쓰는 언어등에 따라 git ignore를 적절히 생성해주는 사이트들도 있다

>> https://www.toptal.com/developers/gitignore

 

gitignore.io

Create useful .gitignore files for your project

www.toptal.com

안드 프로젝트 이그노어는 여기서 도움을 받을 것이다.... 그런 프로젝트들은 구조가 너무 복잡시럽기땜시....

 

내가 작성한 파일은 다음과 같다(꼴랑두줄)

.gitignore 사용법을 좀 기억해두고자 주석으로 메모를 조금 해뒀다

# Just file name 그냥 파일 이름
# /[filename] : file on certain route
# [dir name]/ : ends with / means it's a directory /로 끝나면 디렉토리
# ![file not to ignore or exception] 
# [route]/**/[all the files have this name]
# *.txt : all txt files

*.o
*.a

 

그리고 Makefile..

이건 빌드할때의 규칙을 설정해둔것으로..

나중에 다른사람이 다운받거나 내가 코드를 조금씩 고치고 계속 새로 빌드해서 실행할 때

해당 디렉토리에서 make 만 치면 설정대로 빌드가 되도록 해둔 것이다.

 

이건 나중에 결국은 알아야겠지만 뭐라는건지 싶으면 몰라도될거같다... 왜냐면 저거 공부하는데만도 나는 시간이 좀 걸렷엇기떄문 ㅠ  걍 이거 없으면 매번 통합개발툴로 빌드하던지 뭐 그렇게하면된다... 배포하는거 아니고 공부하는거니깜...

파일명은 Makefile (확장자x)

 

나는 아래와 같이 작성해주었다

쓰레드를 쓰는 코드라 옵션으로 -lpthread 추가..

 

CC = gcc
CFLAGS =
LDFLAGS = -lpthread

.SUFFIXES : .c .o
.c.o :
	$(CC) -c $(CFLAGS) $<
	
ALL = shm sipc1 sipc2 sipc_sem sipc_m

all : $(ALL)

shm : shm.o
	$(CC) -o $@ $< $(LDFLAGS)
	
sipc1 : sipc1.o
	$(CC) -o $@ $< $(LDFLAGS)

sipc2 : sipc.o
	$(CC) -o $@ $< $(LDFLAGS)

sipc_sem : sipc_sem.o
	$(CC) -o $@ $< $(LDFLAGS)

sipc_m : sipc_m
	$(CC) -o $@ $< $(LDFLAGS)

clean :
	rm -rf *.o $(ALL)

 

 

 

 

4. git add / git commit

add는 스테이지..(앞으로 깃에 올라갈애들이 대기하는 곳..)에 올리는 것이고 (깃이 기억할 상태를 조성?하는것)

commit 은 깃에게 이상태를 기억해! 하는것이다

push 는 기억한 상태를 온라인에도 동기화시키는 것이다..

 

스테이지에 착착올리고 하나둘셋~ 하고 사진 촥 찍는다고 생각하면 된다 하하하

 

git add . << 에서 . 은 전부라는 뜻이당

git status 는 상태를 볼 수 있다

지금 다 새파일들이라서 newfile로 뜸

 

이제 커밋을 해보자

git commit

을 하면 현재 스테이지에 있는 애들이 다 저장되는데

보통 -m "커밋메시지"

옵션을 넣는다...

뭔커밋인지 요량껏 쓰면된다.

 

그리고 git status 로 확인하면

당신의 브랜치가 origin/main 으로부터 1개 앞선다고 나오는데

원격 레포지토리(깃허브) 보다 내가 1개 커밋을 많이했다는 뜻이당

 

고로 지금 한 커밋을 깃허브에도 업데이트 해주어야한당

 

5. git push

git push [원격저장소이름] [푸시하려는브랜치]

젤 기본값은 origin 과 main 이다

(원래 master 였는데 main으로 바꼈네...몰랐네...)

 

이렇게 하면

 

짜잔!

 

 

오늘 새로 올린 IPC_Synchronization 폴더와 내용물들이 깃허브에 잘올라갔당

 

 

 

엄청 많은 내용들이 생략되었으나

세상에 좋은 책도 글도 너무 많으니 참고할 수 있을거라고 생각한다.

 

나는 그저 처음할때 너무 막막하고 자세한 설명들이 더 어렵게 느껴졌었기에 허접하지만 이렇게 글을 남겨본다

 

 

그럼 굿나잇 나자신!!

728x90
728x90

나는 랩탑 하나를 우분투를 깔아 쓰고있다 (20.04LTS) 듀얼부트가 아니닷...

위 에러메시지에 대한 다른 해결책이 구글에 많이 나오는데

대부분 서버컴퓨터거나 VM위에 깔아둔 우분투거나 듀얼부팅이거나 해서 나와는 상황이 약간씩 달랐다...

 

근데 루트 용량이 부족하다고 며칠전부터 시위를 해서

쓸데없는 저널같은거 정리좀 해줬더니 또 잠잠하다가.... 다시 경고가 뜨기시작했다

사용량을 보니 써야하는 프로그램들이 자리를 많이 차지해서 자잔한거 지워봐야 소용이없을 것 같았다

 

그래..백업..해놓고 늘려줄게..방법을 찾을게...하다가

홈 디렉터리를 압축해보려했는데 이것도 용량없다고 못하게하고...

( gzip: stdout: No space left on device )

 

 

그러다가...

너무 꽉 차버린나머지

부팅이되지않았다.....

 

아따메... 그래도 일주일에 한번이상 백업해둔 데이터가있기에 일부 날려먹을 각오를 하고

 

부팅 USB를 만들어서 Live mode 로 진입한 다음

GParted 를 이용해 파티션 크기를 조정했다.

 

아래 블로그를 보고 따라했고 Home partition 앞부분을 줄인다음 root partition 을 10G 늘려주었다

 

https://heisanbug.tistory.com/18

 

결과는 아주 성공적! 백업 걱정을 했는데 아직까진 날려먹은것도 없어보인다

 

할일 짱많은데 왜이러는거야 나한테!ㅠ 그래도 잘 해결되서 다행이당

728x90
728x90

본 글은 대학 수업 듣다가 하도 이해가 안돼서 정리하면서 이해해보고자 쓰는 글입니닷

 

Process 들은 분리 된 데이터 영역을 가진다.

 

그치만 우린 그 프로세스 간에 데이터를 주고받고싶을때가 있는 것이다.

 

이를 IPC(Inter-Process Communication)라고 하고 그 수단은 크게 두가지로 나뉘고 또 그 두개에서 세부적으로 나뉜다.

 

내가 수업에서 배운 큰 분류는 다음과 같다.

Message passing
커널이 관리, 동기화 문제 신경쓸 필요X
오버헤드 큼
PIPE
부모-자식 프로세스간 단방향 전송(read or write)
FIFO
부모자식 관계가 아닌 프로세스들도 통신 가능
Shared Memory
메모리 공간을 할당받아 2개 이상의 프로세스들이 같은 메모리공간에 접근함
동기화문제가 생길 수 있다. < 보통 세마포어를 써서 해결

shared memory 관련 system call 사용
MMP
(Memory mapped file) 을 shared memory로 사용

 

PIPE 는 시스템콜 PIPE로 생성할 수 있으며 그냥 파일디스크립터 처럼 read, write 시스템콜을 사용하면 된다.

파일 디스크립터를 복사하는 dup라는 기능도 있다.

이걸 사용하면 STD_OUT에 써지는 내용을 PIPE에도 동일하게 보내거나

STD_OUT은 닫아버리고 모든 출력을 PIPE가 받도록 할 수도 있다.

 

FIFO는 자료구조의 FIFO가 맞다.

프로세스로부터 메시지를 받아 요청이 들어올 때마다 선입선출시킴..

mkfifo 시스템콜로 FIFO를 만들고 그 객체를 open, close, read, write 할 수 있다.

 

Shared Memory 내 머리를 터지게 하는 유용한 기능

사실 쉐어드메모리 개념 자체가 아니라 동기화문제가 구웨엑이다..

서로 다른 둘 이상의 프로세스가 같은 메모리를 함께 사용한다.

일단 관련 시스템콜은 아래와같다.

 

shget :운영체제야 쉐어드메모리 줘 없으면 만들어서 줘!!!

 - shared memory ID 를 리턴.

shmat : Virtual address 에 physical memory 주소 연결해줘!!!(= mapping)

 - 쉐어드메모리의 포인터가 리턴

  그리고 이때 얘가 가리키는 주소에는 flag로 0이 들어있다

shmdt : 연결한거 떼줘!!

 - 정상적으로 수행 시 0 리턴

 

할당해제는 컨트롤 오퍼레이션을 사용한다

shmctl( 쉐어드메모리ID, IPC_RMID, 0 )

두번째 인자로 IPC_RMID 를 주면 system 상에서 shared memory가 사라진다. 옵션은 보통 NULL로 준다. 

 

그리고 Memory mapped file

디스크상의 파일을 Virtual address와 mapping 해서 쓰는것인데

file 에 바로 쓰므로 file I/O와는 다르다...........고 하나

실상 페이지가 메모리에서 내려갈 때 변경사항이 반영되므로 File I/O와 섞어쓰다가는 동기화문제가 생긴다고 한다.

 

 

관련 시스템콜은

mmap : VA를 할당

munmap: 할당 해제

이 있다.

mmap 은 파라미터가 좀 복잡하다고 느껴지는데... 순서대로

mapping할 address : 0추천 > 시스템이 알아서 고름

사이즈

prot : PROT_READ, PROT_WRITE, PROT_EXEC, PROT_NONE

flag : offset, 보통 0 넣으면 됨

 

이렇게 4개가 들어간다

 

끝!

 

 

 

 

728x90
728x90

실습 코드에

close(1); <<요런 라인이 있었다..

 

1이 뭐여?

 

알고보니 unistd.h 에서 사용하는 파일디스크립터(file descriptor)의 매크로이당.. ( POSIX API의 일부란다)

 

매크로란 인수형 등의 인자를 쉽게 기억하기(?) 위해

또는 코드 가독성을 올리기위해 사용하는 것...

아래 표의 첫번째칸 값을 넣으나

세번째칸 값을 넣으나 똑같다는 것이다

보통 C에서 대문자로 표현된당..

 

 

고로 close(1) 은

스탠다드 아웃풋 디스크립터를 닫는다 즉, 더이상 본 프로세스에서 표준 출력을 쓰지 않겠다 라는 것이다.

close(0) 은 표준입력을 받지 않겠다는 것이다.

위 세개의 파일 디스크립터, 스트림은 open을 따로 하지 않아도 프로세스 생성 시 자동으로 생성된다.

 

자동으로 생성되는 것에 대한 내용은 여기에 썼었다.. 물론 구글에 더 좋은 글이 많을 것이당

 

2021.10.30 - [프로그래밍 공부/OS] - [Linux] 표준 입력, 표준 출력, 표준 에러 출력, 파일디스크립터

 

[Linux] 표준 입력, 표준 출력, 표준 에러 출력, 파일디스크립터

리눅스 공부하면서... 이해한걸 또 까먹을까봐 내식대로 적어두려함 출처는 학교 리눅스 수업 + 모두를 위한 리눅스 프로그래밍(아오키 미네로, 2018) 이다. 컴퓨터는 기본적으로 1차원 바이너리

holsui.tistory.com

 

 

나는 close(1) 이녀석 행색이 맘에안들어서

close(STDOUT_FILENO) 으로 변경하였따....

 

 

참고자료 : 오늘 날 도와준 위키피디아 땡큐!

 

728x90
728x90

*Ubuntu 20.04 에서 컴파일했습니당..

 

 

빌드시 아래 메시지가 뜬다면....

pthread library 가 제대로 링크 되지 않은것이다...

 

undefined reference to 'pthread_cancel'

undefined reference to `pthread_create'

undefined reference to `pthread_join'

 

이거 배워놓고 자꾸 잊어먹는다...

 

pthread.h 를 포함하고 pthread 관련 함수 사용시

compile 시 -lpthread 옵션을 꼭 넣어주어야한다!

 

make file 작성시에는

CC = gcc
CFLAGS =
LDFLAGS = -lpthread


[target] : [prerequisites(.o file 등)]

        $(CC) -o $@ $< $(LDFLAGS)

 

요렇게 작성하면 되고

 

직접 컴파일할때는

 

gcc -o [target] [소스코드] -lpthread

 

이렇게 옵션 넣어주면 된다...

 

그러나 lpthread 말고 pthread 옵션을 넣어도 되는데

둘의 차이는

lpthread 는 pthread 라이브러리와 링크만 해주고

pthread 는 라이브러리 링크+매크로 사용이 가능하다.

그래서 pthread 사용을 추천하는 글이 많다...

그러나 pthread 옵션은 운영체제에 따라 동작하지 않을 수 있다... 아마 그래서 내 실습자료도 lpthread 옵션을 사용한듯허당!

 

 

출처 :

728x90
728x90
더보기

「Linux, system call, operating system, asynchronus programming, 비동기 프로그래밍


오늘은 학교 과제하다가 잘 복습해두고픈 내용이 있어서 써본다

Linux system programming 수업에서 요즘 Signal 부분 과제를 하고있다...

오늘 실습한 코드는signal(알람수신자) 과 alarm(알람발신자) 을 사용해서 동기적 프로그래밍하기!

나를 혼란스럽게 했던 내용...
* signal 은 signal 보내는게 아니라 받는 함수다 ㅡㅡ .... 진짜 넘하지않냐....
* 뭐..안넣어도 세상이 워낙 좋아 컴파일이 되긴했지만 alarm 사용을 위해 unistd.h 헤더 포함시켜주기...
*signal인터페이스

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

첫번째 인자 signum 은 MACRO를 사용한다 ( SIGINT, SIGBUS,SIGALRM,SIGTERM 등...)
(man signal 참고*)
두번째 인자는 함수 포인터이다... 위 형식에 맞게 함수를 선언하고 넣어주면 된다.

첫번째 인자에 해당하는 signal 을 받으면 두번째 인자의 함수가 실행된다.
default 동작도 있다(무시, 종료 등..)


흐름은....
1. alram signal 을 받았을 때(alarm 함수를 통해 'SIGALRM' 시그널 보냄) 어떤 동작을 수행할지 변경하기위해
SigAlarmHandler 함수를 만든다.(이 함수가 signal 의 두번째 인자, 함수 포인터로 들어간다)
SigAlarmHandler :
여기에는 점을 하나 찍어주는 코드와
signal을 다시 호출하는 코드가 들어간다.
( 여기에서 또 두번째 인자로 핸들러를 재귀적으로 넣어주는데, 일부 운영체제에서 핸들러는 한 번 수행된 뒤 초기화되기 때문이다...)

2. 최초로 signal 을보낼 setPeriodicAlarm 함수를 선언해준다.
signal함수로 SIGALRM 받았을 시의 Handler를 설정해주고
alarm() 호출! 파라미터는 시간이 들어간다 (unsigned int, 초단위.. )
0이면 pending 중인 모든 알람이 취소된다

3. main 에서 setPeriodic Alarm 을 호출한다...

그러면 다른 동작이 모두 종료될때까지 반복해서 alarm handler 에 등록한 내용이 주기적으로 수행된다.

실습코드

#include <stdlib.h> #include <stdio.h> #include <signal.h> #include <unistd.h> static unsigned int AlarmSecs; // 함수 종료시에도 값 유지되는 전역변수 // static : 다른 파일 접근을 막기 위함 // void SigAlarmHandler(int signo) { // 한 번 호출 후 Hanlder 사라지는 OS가 있으므로 // 재귀적으로 재등록 if( signal(SIGALRM, SigAlarmHandler) == SIG_ERR) { perror("signal"); exit(1); } // 다시 알람 시스템 콜 요청 // 전역변수 사용(함수가 사라지므로) alarm(AlarmSecs); /* DO something */ // 버퍼캐시 바로 flush printf("."); fflush(stdout); return; } int SetPeriodicAlarm(unsigned int nsecs) { if( signal(SIGALRM, SigAlarmHandler) == SIG_ERR) { return -1; } // 정상종료 시 -1 return AlarmSecs = nsecs; alarm(nsecs); return 0; } int main() { int i,j; printf("Doing something every one sec.\n"); // 1초마다 정해진 동작 하는 함수(asynchronus) SetPeriodicAlarm(1); //위 알람과 상관없이 자기 일 하는 코드.. // asynchronuos 함을 더 직접적으로 보기 위해 내맘대로 넣어본 yum! for(i = 0;i < 1000000;i++){ if( i%100000 == 0) printf("\nyum!\n"); for(j = 0; j<20000; j++) {} } return 0; } 67,1 Bot


어마어마한루프는... 일부러 시간끌기용으로 넣어보았다 숫자는 별의미없음

수행결과는 이렇게 나왔당


끝!

참고한것 :학교수업자료, 아오키미네로 「모두를위한 리눅스 프로그래밍」, man alarm

728x90
728x90

학교과제중에 진짜 미쳐버릴거같았던 에러.... 오만곳을 다뒤졌는데 시원한해결책을 못찾고 3시간 허비...

애먼 컴파일러가 잘못된줄알구....버전 바꿧다가막...난리침

 

결론부터 말하자면 컴파일러가 아니라 함수 파라미터가 잘못된것이었음!!!

 

나는 아래 함수에서  strtok 함수를 쓰며 에러가 났는데, strcpy 도 파라미터를 잘못넣으면 비슷한 에러메시지가 난다...

캐릭터배열 너무 다루기 힘들다 흑흑흑

좀 투박하고..더좋은 방법이있을거같지만 일단 돌아가니 제출하고 자야지 ㅠ

 

아래 코드는 실제 과제내용은 당연아니고 오류나는 부분만 실험해보려고 이래저래 돌려본 코드...

 

오류나는 코드

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

//오류나는경우

int splitstr(char* cmd) {
    char *ptr =strtok(cmd, " ");
    while (ptr != '\0')
    {
        printf("%s\n", ptr);
        ptr = strcpy('\0', " ");
    }
    
}

int main(int argc, char const *argv[])
{
    splitstr("hello hi hi");
    return 0;
}

 

고친 코드(2줄 추가됨)

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


int splitstr(char* cmd) {
    char str1[100];					//char 배열 선언하고
    strcpy(str1, cmd);					//복사..
    char *ptr =strtok(str1, " ");
    while (ptr != '\0')
    {
        printf("%s\n", ptr);
        ptr = strtok(NULL, " ");
    }
    
}

int main(int argc, char const *argv[])
{
    splitstr("hello hi hi");
    return 0;
}

   

 

728x90

+ Recent posts