Linux学习之C语言的进程与线程编程
前言
繼續Linux的學習,學到了Linux系統下的進程與線程的概念,布置了有關其的實驗題,用C語言編程啟動進程線程,習慣了Java多線程編程,這次在Linux下玩一玩C語言進程線程編程。
本文原創,創作不易,轉載請注明!!!
本文鏈接
個人博客:https://ronglin.fun/?p=155
PDF鏈接:見博客網站
CSDN: https://blog.csdn.net/RongLin02/article/details/115419994
準備工作
環境與配置
主機:聯想Y7000P;64位windows10;CPU:i7-9750H;顯卡:GTX 1660 Ti;內存:16G
虛擬機:Ubuntu 18.04 LTS;硬盤100G;內存4G;64位;4核心
Linux內核:5.11.8
安裝IDE
工欲善其事,必先利其器,首先安裝一個好用的C語言IDE,C語言在Linux下的IDE有很多,比如geany,codeBlocks等等,當然也有大佬用文本編輯器vim nano gedit等直接寫,然后用gcc編譯也是可以的。我這里用Windows下我比較喜歡的一個編譯器codeBlocks。
方法一
2022.2.28可用
輸入以下代碼
方法二
為了更方遍的調試,先安裝一下GCC。輸入:
sudo apt install gcc然后安裝codeBlocks和其所依賴的庫,輸入:
sudo add-apt-repository ppa:damien-moore/codeblocks-stable sudo apt-get update sudo apt-get install codeblocks sudo apt-get install codeblocks-contrib等待其自己安裝完就行了。
如果上面那個ppa庫沒法用還可以用下邊這個
補充資料:
PPA:PPA全稱為 Personal Package Archives(個人軟件包檔案),是 Ubuntu Launchpad 網站提供的一項服務,當然不僅限于 Launchpad 。它允許個人用戶上傳軟件源代碼,通過 Launchpad 進行編譯并發布為二進制軟件包,作為 apt/新立得源供其他用戶下載和更新。
sudo add-apt-repository ppa:pasgui/ppa這句代碼,會在/etc/apt/sources.list.d目錄下添加PPA源,供我們使用,所以如若想刪除添加的PPA源,到/etc/apt/sources.list.d目錄下,刪除對應的文件即可。
安裝完成后,直接在終端中輸入codeblocks,彈出來界面,點擊ok即可。
更多關于Ubuntu 18.04安裝codeBlocks的方法,可以參考:https://blog.csdn.net/AAMahone/article/details/86531631
題外話
界面太小
由于是虛擬機,可能界面比例很小,導致 代碼編輯區很小,看起來很不舒服,大概我知道的有兩種解決:
方法一:把虛擬機界面最大化
我的虛擬機是VirualBox,要想調整虛擬機界面大小,要先安裝 增強模式,如果之前安裝過了,就可以直接調整界面大小了。安裝增強模式也很簡單,在虛擬機菜單欄設備–安裝增強功能,安裝完成后,返回桌面,會發現多了一個光盤,點擊光盤,在標題欄的下方右側,也就是右上角,有一個 運行程序,點擊,然后重啟Ubuntu即可。一定要點擊運行程序,要不然增強功能不生效!
方法二:調整codeblocks各個欄目的大小
codeblocks的GUI設計很人性化,每一個欄都可以調整大小,同時也可以在菜單欄view中關閉不需要顯示的部分,例如我個人的喜歡布局如下:
中文下方紅色波浪線
這個功能其實是拼寫糾錯功能,可能是在Ubuntu下對中文還沒完全適配好,導致輸入中文就出現紅色波浪線,尤其是在printf中和注釋里,讓人眼花
菜單欄Plugins–Manage plugins 找到 SpellChecker disable它,然后重啟codeblocks就行了。
創建進程
實驗簡述
實驗說明:
學會通過基本的Linux進程控制函數,由父進程創建子進程,并實現協同工作。創建兩個進程,讓子進程讀取一個文件,父進程等待子進程讀完文件后繼續執行。
解決方案:
進程協同工作就是要協調好兩個或兩個以上的進程,使之安排好先后次序并依次執行,可以用wait()或者waitpid()函數來實現這一點。當只需要等待任一子進程運行結束時,可在父進程中調用wait()函數。若需要等待某一特定子進程的運行結果時,需調用waitpid()函數,它是非阻塞型函數。
程序框架
當fork( )調用成功后,父子進程完成各自的任務,但當父進程的工作告一段落,需要用到子進程的結果時,它就停下來調用wait( ),一直等到子進程運行結束,然后利用子進程的結果繼續執行,這樣就圓滿地解決了父子進程間的協同工作問題。
源代碼
指導書都寫得這么詳細了,那么直接開整吧
有關創建project的操作和Windows下的操作一樣,菜單欄File–new–Project–Console application
我在/home/ronglin/code/gnu/新建一個project文件夾,用來存放C項目,要選擇c代碼,本次實驗項目名稱為create_process
然后一路next就行了。當然因為本次實驗實際上只需要一個.c文件就行了。也可以只是新建一個.c文件,菜單欄File–new–File..–C/C++ source然后也是填寫信息,一路next就行了,但是缺點就是單獨一個.c/cpp文件是沒辦法用codeblocks的調試功能的。
在Sources的main.c中寫代碼,如果是main.cpp說明新建的是一個c++程序,雖然大概差不多,但是還是推薦c和c++代碼分離。
因為子進程還要打開一個文件,我在工程目錄下新建一個text.txt文件用于測試。
然后就是頭禿的過程了。
fork()創建
#include<sys/types.h> #include<sys/wait.h> #include<stdio.h>#define COLMAX 1024 //每一個字符串的最大長度(列) #define ROWMAX 64 //字符串最大個數(行)/* 本代碼實現用子進程打開同目錄下的text.txt文件 并且父進程輸出內容 */int main() {int p_id = -1;if( (p_id=fork()) == -1 ) //子進程創建失敗{printf("Process_1 Create Error\n");}else if(p_id == 0) //子進程部分{printf("%d Process Start Work\n",getpid());char text[ROWMAX][COLMAX]={0};FILE *fp = fopen("./text.txt","r+");//打開文件if( fp == NULL )//打開文件失敗{printf("Fail to open file!\n");}else{int i=0;while( (fscanf(fp,"%s",text[i])) != EOF){printf("%s\n",text[i]);i++;sleep(1); //等待1s方便查看輸出}}fclose(fp);exit(0);}//父進程部分waitpid(p_id,NULL,0);//阻塞等待printf("%d proccess is end\n",p_id);return 0; }
由于是用的scanf,遇到空格就讀入完畢,所以結果呈現如上圖。
vfork()創建
因為fork()創建的子進程其實是父進程數據的copy,也就是說父子進程的數據并不是共享的,子進程只是父進程的翻版,類似于c語言函數中的傳遞形式參數,要想數據共享,其實也有很多方法,資料書上提到很多CLONE_開頭的標志位就是控制哪些東西是父子進程共享的。不過有更簡單的vfork()函數,其實本質上是一樣的,都是調用內核函數do_fork()。接下來就實現,子進程讀取文件,然后父進程輸出,需要注意的是,不論多進程還是多線程,數據一旦共享,會涉及到安全問題,不過vfork()創建子進程之后,父進程就會阻塞,所以就沒安全問題了。
直接看源碼吧
輸出結果同上。
線程共享進程中的數據
實驗簡述
實驗說明:
了解線程與進程之間的數據共享關系。創建一個線程,在線程中更改進程中的數。
解決方案:
在進程中定義共享數據,在線程中直接引用并輸出該數據。
程序框架:
源代碼
創建第二個project–share_thread,因為有一部分Java多線程開發的基礎,所以直接開整。
#include <stdio.h> #include <pthread.h> #include <unistd.h>static int shdata=4;void *create(void *arg) {printf("new pthread...\n");printf("shdata data = %d \n",shdata);return (void *)(0); }int main() {pthread_t mythread ;int error = 0;error = pthread_create(&mythread,NULL,create,NULL);if(error){printf("pthread_create is not created...\n");return -1;}sleep(1);printf("pthread_create is ok...\n");return 0; }寫完代碼發現,編譯一直報錯,查閱資料才知道,pthread庫不是Linux系統默認的庫,需要使用庫libpthread.a
如果是用gcc指令編譯則應該輸入這個
gcc test.c -lpthread -o pthread
如果是codeblocks就添加庫就行了,首先需要在終端中輸入:
locate libpthread.a先找一下 文件在哪
有兩個,一般用/usr目錄下的,將/usr/lib/x86_64-linux-gnu/libpthread.a復制下來。
codeblocks,菜單欄Settings–Compiler,左側Global compiler settings,中間Linker settings
在左側Link libraries中 add 剛剛復制好的路徑,右側Other linker options,輸入-lpthread
然后ok就行了.
運行成功.
多線程實現單詞統計工具
實驗簡述
實驗說明
多線程實現單詞統計工具。
解決方案
區分單詞原則:凡是一個非字母或數字的字符跟在字母或數字的后面,那么這個字母或數字就是單詞的結尾。
允許線程使用互斥鎖來修改臨界資源,確保線程間的同步與協作。如果兩個線程需要安全地共享一個公共計數器,需要把公共計數器加鎖。線程需要訪問稱為互斥鎖的變量,它可以使線程間很好地合作,避免對于資源的訪問沖突。
程序框架
源代碼
創建第三個project–words_counter,先在根目錄下新建兩個txt文件,一共3+6=9個單詞
代碼見上,然后就是給main函數傳參數,菜單欄Project–Set programs’ arguments…,左側Global compiler settings,選中Debug,在下邊的Program arguments中添加要參入的參數./text1.txt ./text2.txt.然后ok.
然后運行查看結果:
成功了,=w=
總結
以上是生活随笔為你收集整理的Linux学习之C语言的进程与线程编程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 两个重要极限_算法数学基础-概率论最重要
- 下一篇: 自动控制原理第二版王建辉_气箱脉冲布袋除