Skip to content

Latest commit

 

History

History
298 lines (192 loc) · 6.2 KB

11.md

File metadata and controls

298 lines (192 loc) · 6.2 KB

在Linux,如果程式碼在背景執行(使用&,加在執行檔後面),就沒辦法使用ctrl+C,需要使用kill

使用ps 指令 ,可以查看執行程式的PID,只要kill PIDnum,就可以把背景執行的程式刪除

gcc georgeMary.c -lpthread: 跑應用程式,使用pthread動態函式庫

race condition

使用公用變數就會發生這種問題

race.c

#include <stdio.h>
#include <pthread.h>

#define LOOPS 100000000
int counter = 0;

void *inc()
{
  for (int i=0; i<LOOPS; i++) {
    counter = counter + 1;
  }
  return NULL;
}

void *dec()
{
  for (int i=0; i<LOOPS; i++) {
    counter = counter - 1;
  }
  return NULL;
}


int main() 
{
  pthread_t thread1, thread2;

  pthread_create(&thread1, NULL, inc, NULL);
  pthread_create(&thread2, NULL, dec, NULL);

  pthread_join( thread1, NULL);
  pthread_join( thread2, NULL);
  printf("counter=%d\n", counter); // 出來的結果不會是0,會在1億和-1億之間
  // 因為組合語言的關係,在程序互相交錯時,裡面的值就會錯亂
    /*
    	R1 = C
    	R1 = R1 + 1
    	C = R1
    */
    /*
    	R1 = C
    	R1 = R1 -1
    	C = R1
    */
}

需要使用

norace.c

#include <stdio.h>
#include <pthread.h>

pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;
#define LOOPS 100000
int counter = 0;

void *inc()
{
  for (int i=0; i<LOOPS; i++) {
    pthread_mutex_lock( &mutex1 );  // 採用互斥鎖的鎖定方式
    counter = counter + 1;
    pthread_mutex_unlock( &mutex1 );
  }
  return NULL;
}

void *dec()
{
  for (int i=0; i<LOOPS; i++) {
    pthread_mutex_lock( &mutex1 );
    counter = counter - 1;
    pthread_mutex_unlock( &mutex1 );
  }
  return NULL;
}


int main() 
{
	pthread_t thread1, thread2;

	pthread_create(&thread1, NULL, inc, NULL);
  pthread_create(&thread2, NULL, dec, NULL);

  pthread_join( thread1, NULL);
  pthread_join( thread2, NULL);
  printf("counter=%d\n", counter);  // 執行幾次都是 0
}

生產者消費者問題

也稱有限緩衝問題(Bounded-buffer problem),如果解決方法不夠完善,則容易出現死結的情況

  • 生產者的主要作用是生成一定量的數據放到緩衝區中,然後重複此過程。與此同時,消費者也在緩衝區消耗這些數據。該問題的關鍵就是要保證生產者不會在緩衝區滿時加入數據,消費者也不會在緩衝區中空時消耗數據。

哲學家用餐問題

需要哲學家同時拿起叉子才會發生問題(死結),這個代表很少發生的Bug,所以在偵測上也會比較麻煩。

  • 做以下兩件事情之一:吃飯,或者思考。吃東西的時候,他們就停止思考,思考的時候也停止吃東西。餐桌上有五碗義大利麵,每位哲學家之間各有一支餐叉。因為用一支餐叉很難吃到義大利麵,所以假設哲學家必須用兩支餐叉吃東西。

semaphore

根據S,判斷可不可以進入程式(S>0),執行P(wait())會減少值(S),執行V(signal())會增加值(S)

thread

有點二進為的感覺,1可以進去,0不可以進去

fork

fork函數可以讓一個應用程式產生很多行程(process),他有傳回值,假如return == 0 代表是新產生的process

posix

  • 可移植作業系統介面(Portable Operating System Interface of UNIX,縮寫為 POSIX ),是一種標準

process

行程,代表一個程式可以運行多次,執行一次多一個行程(有的也會出現多個行程),行程大多運行在背景,使用ps可以查看process

fork2.c

#include <stdio.h> 
#include <sys/types.h> 
#include <unistd.h>  // 在linux環境下才可以引入

int main() { 
    printf("%-5d : enter\n", getpid());  // getpid() 可以查看thread進行狀況
	/* 還沒有fork(),只有一個process
4100  : enter
    */
    fork(); // 使用unistd.h,一個行程分叉成父子兩個行程
    printf("%-5d : after 1st fork\n", getpid());
	/* fork()一次,兩個個process 
4100  : after 1st fork
4101  : after 1st fork
	*/
    fork(); // 兩個行程又分別分叉出兩對父子,所以變成四個行程。
    printf("%-5d : Hello world!\n", getpid());
    /* fork()兩次,四個process 
4100  : Hello world!
4102  : Hello world!
4101  : Hello world!
4103  : Hello world!
	*/
}

多工處裡

現在作業系統,一開始會執行init,後面會使用fork分出一個shell,讓我們可以使用指令控制電腦做其他事情。有多工,在電腦運行應用程式當機的時候,只要切斷fork的分支就可以,不用重新開機

exec

process的切換

有exec這種字的,都會切換到其他的執行碼,下面的內容就不會執行了

execvp1.c

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

int main() {
  char *arg[] = {"ls", "-l", NULL };
  printf("execvp():before\n");
  execvp(arg[0], arg);  // 使用unistd.h,可以把這個 process 換成上面的指令 ls
  printf("execvp():after\n");  // 這行不會執行
}

system

mysystem1.c

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

int mysystem(char *arg[]) {
  if (fork()==0) {  // let child process exec ls -l, parent keep going
    execvp(arg[0], arg); // child : exec("ls -l")
  }
  int status;
  wait(&status); // wait通常搭配fork來用,讓fork執行完才retrun
  return status;
}

int main() {
  char *arg[] = {"ls", "-l", NULL };
  mysystem(arg);
  printf("main end!\n");
}

system1.c

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

int main() {
  system("ls -l");  // c的原生函數,可以呼叫指令,不會結束到原生函數
  printf("main end!\n");
}

zombie

父還沒結束,子就不會結束,記憶體會被占用。如果可以遠端讓別人的電腦使用fork指令,就會讓電腦爆炸(殭屍炸彈)

zombie.c

#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
int main () {
  pid_t child_pid;
  /* Create a child process. */
  child_pid = fork ();  // 創造進程讓電腦產生垃圾
  if (child_pid > 0) {
    /* This is the parent process. Sleep for a minute. */
    sleep (60);
  } else {
    /* This is the child process. Exit immediately. */
    exit (0);  // child pocess become zombie
  }
  return 0;
}

使用fork()和execvp()可以做出shell、bash....