linux內核棧,內核同步,用戶空間線程同步

2020-08-28 linux技術棧

一、內核棧

1.每當創建一個進程(主線程),用戶線程,內核線程時,內核都會給這個進程或線程動態創建一個內核棧,在內核空間,換存在cache中。內核棧裡有個thread_info指針,指向task_struct結構體(cpu根據這個來調度,所以可以實現調度的基本單位是線程)。
2.進程用戶棧:創建一個用戶進程(主線程)時,需要創建一個mm_struct,使其task_struct中的mm指針指向此mm_struct
3.用戶線程和其他線程共享用戶棧「:創建一個用戶線程時,使其task_struct中的mm指針指向一個已存在的mm_struct。這些線程共用一個進程地址空間。
4.內核線程沒有用戶棧:創建一個內核線程時,使其task_struct中的mm指針為空。
5.對於進程地址空間,用戶棧存放局部變量等東東,數據段.data存放全局變量和static變量(static局部變量)
6.對於內核地址空間(0xc000 0000以上的),其是不是也分為數據段代碼段呢?是不是數據段也存放著內核的全局變量和statci變量呢?
有一點可以知道,內核空間有n多個內核棧,有多少線程就有多少內核棧,但每個棧都很小(不像進程空間的用戶棧,一個進程只有一個用戶棧,但很大)
7.從用戶態進入內核是什麼意思?
先看 進程上下文 中斷上下文 / 用戶空間 內核空間
比如一個進程在他的地址空間(0xc000 0000 以下)裡面玩的好好的,突然要調用一個函數(系統調用),而這個函數位於地址0xc666 6666(整個內核地址空間即0xc000 0000以上有什麼函數和符號,其地址可以理解為都是已經確定好的),於是就要跑到0xc666 6666地址去執行,此時算是進入內核態了。在執行0xc666 6666這個函數時,函數裡面的局部變量需要保存在這個進程的對應的內核棧裡面,內核棧<8KB,不要使用過大的變量(如大的數組),否則溢出死機。

需要C/C++ Linux伺服器架構師學習資料私信「資料」(資料包括C/C++,Linux,golang技術,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒體,CDN,P2P,K8S,Docker,TCP/IP,協程,DPDK,ffmpeg等),免費分享


驅動裡的全局變量,局部變量,static局部變量放在哪裡了?
這些變量可以被不同的應用程式共享嗎?
如下:

/********************************base.c**************/ include <linux/delay.h> include <linux/kernel.h> include <linux/init.h> include <linux/fs.h> include <linux/time.h> include <linux/moduleparam.h> include <linux/errno.h> include <linux/cdev.h> include <linux/list.h> include <asm/uaccess.h> include <asm/unistd.h> ifdef DEBUG 34; DBG(%s, %s(), %d): &else endif 34;misc_test_dev&define NUM_BYTES 32 int a=1;ssize_t misc_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos) { return 0; //return the bytes quantity have copied} ssize_t misc_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) { char *kbuf=kmalloc(1,GFP_KERNEL); *kbuf++; printk(&34;,*kbuf,kbuf); int b=2; b++; printk(&34;,b,&b); static int c=2; c++; printk(&34;,c,&c); a++; printk(&34;,a,&a); return count ; //return the bytes quantity have copied} static int misc_release(struct inode *inode, struct file *filp) {DBG(&34;); return 0; } static int misc_open(struct inode *inode, struct file *filp) { DBG(&34;); return 0; } static struct file_operations dev_fops = { .owner = THIS_MODULE, .open = misc_open, .read = misc_read, .write = misc_write, .release= misc_release, }; static struct miscdevice misc = { .minor = MISC_DYNAMIC_MINOR, .name = DEVICE_NAME, .fops = &dev_fops, }; static int __init dev_init(void) { int ret; ret = misc_register(&misc); DBG (DEVICE_NAME&34;); return ret; } static void __exit dev_exit(void) { DBG (DEVICE_NAME&34;); misc_deregister(&misc); } module_init(dev_init); module_exit(dev_exit); MODULE_LICENSE(&34;); MODULE_AUTHOR(&34;);

/********************************readtest.c**************/ include <unistd.h> include <sys/types.h> include <sys/ioctl.h> include <linux/fs.h> include <string.h> ifdef DEBUG 34; DBG(%s, %s(), %d): &else endif 34;open file & insmod base.ko DBG(/work/linux/test/base.c, dev_init(), 98): misc_test_dev init[root@FriendlyARM /] [root@FriendlyARM /] //ctrl+c斷掉,然後再次執行一次[root@FriendlyARM /]include<stdio.h>include<stdlib.h>include<pthread.h> ifdef DEBUG 34;%s(),%d:&else endif pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;pthread_cond_t cond = PTHREAD_COND_INITIALIZER; int count = 0; void *decrement(void *arg) { DBG(&34;,count); pthread_mutex_lock(&mutex); DBG(&34;,count); if (count == 0) pthread_cond_wait(&cond, &mutex); count--; DBG(&34;,count); pthread_mutex_unlock(&mutex); DBG(&34;,count); return NULL;} void *increment(void *arg) { DBG(&34;,count); pthread_mutex_lock(&mutex); DBG(&34;,count); count++; DBG(&34;,count); if (count != 0) pthread_cond_signal(&cond); DBG(&34;,count); pthread_mutex_unlock(&mutex); DBG(&34;,count); return NULL;} int main(int argc, char *argv[]) { pthread_t tid_in, tid_de; pthread_create(&tid_de, NULL, (void*)decrement, NULL); sleep(2); pthread_create(&tid_in, NULL, (void*)increment, NULL); sleep(5); pthread_join(tid_de, NULL); pthread_join(tid_in, NULL); pthread_mutex_destroy(&mutex); pthread_cond_destroy(&cond); return 0;}

等待線程:

pthread_cond_wait前使用pthread_mutex_lock先加鎖
pthread_cond_wait內部會解鎖,然後等待條件變量被其它線程激活
pthread_cond_wait被激活後會再自動加鎖
pthread_cond_wait返回之後需要使用pthread_mutex_unlock釋放鎖
激活線程:
pthread_cond_signal前使用pthread_mutex_lock加鎖(和等待線程用同一個鎖)
pthread_cond_signal發送信號
pthread_cond_signal返回之後需要使用pthread_mutex_unlock釋放鎖

相關焦點

  • ARM Linux系統中的用戶棧與內核棧
    在Linux系統上,一個進程有兩種不同的棧,一種是用戶棧,另一種是內核棧。用戶棧用戶棧就是應用程式直接使用的棧。如下圖所示,它位於應用程式的用戶進程空間的最頂端。應用程式在剛剛啟動的時候(由fork()系統調用複製出新的進程),新的進程其實並不佔有任何棧的空間。當應用程式中調用了函數需要壓棧時,會觸發一個page fault,內核在處理這個異常裡會發現進程需要新的棧空間,於是建立新的VMA並映射內存給用戶棧。
  • 淺談Linux 中的進程棧、線程棧、內核棧、中斷棧
    內核將棧分成四種:進程棧線程棧內核棧中斷棧一、進程棧進程棧是屬於用戶態棧,和進程 虛擬地址空間 (Virtual而將較低的3G字節(0x00000000-0xBFFFFFFF)供各個進程使用,稱為 用戶空間。每個進程可以通過系統調用陷入內核態,因此內核空間是由所有進程共享的。雖然說內核和用戶態進程佔用了這麼大地址空間,但是並不意味它們使用了這麼多物理內存,僅表示它可以支配這麼大的地址空間。它們是根據需要,將物理內存映射到虛擬地址空間中使用。
  • Java+Linux,深入內核源碼講解多線程之進程
    2、內核裡,並不嚴格區分進程和線程。3、從內核的角度看,調度單位是線程 (即執行流)。可以把線程看做是進程裡的一條執行流,1個進程裡可以有1個或者多個線程。4、內核裡,常把進程稱為 task 或者 thread,這樣描述更準確,因為許多進程就只有1條執行流。5、內核通過輕量級進程 (lightweight process) 來支持多線程。
  • Linux內核的同步機制
    一、引言 在現代作業系統裡,同一時間可能有多個內核執行流在執行,因此內核其實象多進程多線程編程一樣也需要一些同步機制來同步各執行單元對共享數據的訪問。
  • linux內核空間與用戶空間
    本文以 32 位系統為例介紹內核空間(kernel space)和用戶空間(user space)。內核空間和用戶空間對 32 位作業系統而言,它的尋址空間(虛擬地址空間,或叫線性地址空間)為 4G(2的32次方)。也就是說一個進程的最大地址空間為 4G。
  • linux用戶空間與內核空間通信——Netlink通信機制
    但是注意雖然Netlink主要用於用戶空間和內核空間的通信,但是也能用於用戶空間的兩個進程通信。只是進程間通信有其他很多方式,一般不用Netlink。一般來說用戶空間和內核空間的通信方式有三種:/proc、ioctl、Netlink。而前兩種都是單向的,但是Netlink可以實現雙工通信。
  • 官方唯一推薦的Linux內核剖析文檔《深入理解Linux內核》免費分享
    從簡單的各種語言開發,到後期的伺服器部署,分布式,集群環境,資料庫相關等,linux都在等著你Linux內核非常龐大,超過600萬行的代碼,所以想要理解Linux內核,不是什麼簡單的事情,在這裡給大家分享關於linux、linux內核方面的PDF《深入理解linux內核 》,目前豆瓣、亞馬遜、噹噹、京東等電子書綜合評分為:9.2。
  • Linux作業系統,為什麼需要內核空間和用戶空間?
    為了保證內核的安全,現在的作業系統一般都強制用戶進程不能直接操作內核。具體的實現方式基本都是由作業系統將虛擬地址空間劃分為兩部分,一部分為內核空間,另一部分為用戶空間。舉個例子,比如我們經常接觸的概念 "堆棧",其實進程在內核態和用戶態各有一個堆棧。運行在用戶空間時進程使用的是用戶空間中的堆棧,而運行在內核空間時,進程使用的是內核空間中的堆棧。
  • linux內核,三十個相關問題
    2) Linux中的用戶模式和內核模式是什麼含意?內核態:進程陷入內核代碼中執行,在內核態將會使用內核棧,每個進程都有自己的內核棧。用戶態:進程在執行自身的應用代碼。當正在執行用戶程序而突然被中斷程序中斷時,此時用戶程序也可以象徵性地稱為處於進程的內核態。因為中斷處理程序將使用當前進程的內核棧。這與處於內核態的進程的狀態有些類似。
  • 聊一聊linux系統的用戶空間和內核空間
    軟體設計的靈感其實都來自於生活:用戶空間就等同於我們理解的人間;而內核空間就等同於所謂的仙界。人間在地上,仙界在天上,地理上是隔離的。linux內核裡的用戶空間和內核空間也是一樣。那麼問題來了,linux內核為什麼要特意劃分內核空間和用戶空間呢?有以下幾方面的原因:1.安全考量整個系統中有各種資源,比如計算資源、內存資源和外設資源。而linux是多用戶、多進程系統。所以,這些資源必須在受限的、被管理的狀態下使用,要不然就陷入了混亂。空間隔離可以保證即便是單個應用程式出現錯誤也不會影響到作業系統的穩定性。
  • Windows作業系統管理進程和線程:內核模式和用戶模式
    這樣,每個進程內的應用程式代碼便可以很方便地調用內核空間中的系統服務。這裡的「很方便」有多層含義,一方面是內核代碼和用戶代碼在一個地址空間中,應用程式調用系統服務時不需要切換地址空間,另一方面是整個系統中內核空間的地址是統一的,編寫內核空間的代碼時會簡單很多。但是,如此設計也帶來一個很大的問題,那就是用戶空間中的程序指針可以指向內核空間中的數據和代碼,因此必須防止用戶代碼破壞內核空間中的作業系統。
  • 透過Linux內核看無鎖編程
    多核多線程已經成為當下一個時髦的話題,而無鎖編程更是這個時髦話題中的熱點話題。Linux內核可能是當今最大最複雜的並行程序之一,為我們分析多核多線程提供了絕佳的範例。內核設計者已經將最新的無鎖編程技術帶進了2。6系統內核中,本文以2。6。10版本為藍本,帶領您領略多核多線程編程的真諦,窺探無鎖編程的奧秘,體味大師們的高雅設計!
  • linux內核講解
    一, Linux內核開發環境搭建1. Linux內核研習與項目實戰專欄介紹2.Linux內核編譯與升級3. Linux內核學習方法論二, Linux內核之Android組件Binder實現4.內核模塊操作,insmod, rmmod, lsmod, dmesg7. 模塊初始化 module_init8.
  • Linux內核之內存管理
    內核用這個結構來管理系統中所有的頁,所以內核知道哪些頁是空閒的,如果在使用中擁有者又是誰。這個擁有者有四種:用戶空間進程、動態分配內存的內核數據、靜態內核代碼以及頁高速緩存。 5、進程地址空間以上我們講述了內核如何管理內存,內核內存分配機制包括了頁分配器和slab分配器。內核除了管理本身的內存外,也必須管理用戶空間中進程的內存。
  • 深入作業系統,從內核理解網絡包的接收過程(Linux篇)
    在Linux內核實現中,鏈路層協議靠網卡驅動來實現,內核協議棧來實現網絡層和傳輸層。內核對更上層的應用層提供socket接口來供用戶進程訪問。5.2 ksoftirqd內核線程處理軟中斷ksoftirqd內核線程:內核線程初始化的時候,我們介紹了ksoftirqd中兩個線程函數ksoftirqd_should_run和run_ksoftirqd。
  • 內核不斷升級 如何學習linux設備驅動
    【IT168技術】面對不斷升級的linux內核、GNU開發工具、linux環境下的各種圖形庫,很多linux應用程式開發人員和linux設備驅動開發人員即興奮,又煩躁。興奮的是新的軟體軟體、工具給我提供了更強大的功能,煩躁的是適應新軟體的特性、搭建新環境是一項非常繁瑣的事情。
  • 鴻蒙內核源碼分析(Task/線程管理篇)
    Task/線程管理篇提示:本文基於開源鴻蒙內核分析,詳細進入kernel_liteos_a查看源碼。本文作者:鴻蒙內核發燒友,將持續研究鴻蒙內核,更新博文,敬請關注。官方文檔是怎麼描述線程基本概念從系統的角度看,線程是競爭系統資源的最小運行單元。線程可以使用或等待CPU、使用內存空間等系統資源,並獨立於其它線程運行。鴻蒙內核每個進程內的線程獨立運行、獨立調度,當前進程內線程的調度不受其它進程內線程的影響。鴻蒙內核中的線程採用搶佔式調度機制,同時支持時間片輪轉調度和FIFO調度方式。
  • 同步Chrome30內核 360極速瀏覽器提速
    Chrome30內核,率先升級到Chromium 30.0.1599.47版本。升級了全新內核後的360極速瀏覽器速度更快,頁面打開速度提升一倍。圖:採用最新Chrome30內核的360極速瀏覽器據了解,此次升級後,360極速瀏覽器更新為最新的Chrome30內核,產品版本號為7.5.0.220。
  • linux內核設計與實現:系統調用
    通過調用perror()函數,可以把該變量翻譯成用戶可以理解的錯誤字符串。  系統調用的實現有兩個特別之處:  1)函數聲明中都有asmlinkage限定詞,用於通知編譯器僅從棧中提取該函數的參數。  2)系統調用getXXX()在內核中被定義為sys_getXXX()。這是Linux中所有系統調用都應該遵守的命名規則。
  • Java 離 Linux 內核有多遠?
    完整的段落如下(雙引號擴起來的幾個段落),有興趣的同學可以詳細閱讀:「 fork 傳遞至 _do_fork 的 clone_flags 參數是固定的,所以它只能用來創建進程,內核提供了另一個系統調用 clone,clone 最終也調用 _do_fork 實現,與 fork 不同的是用戶可以根據需要確定 clone_flags,我們可以使用它創建線程