❶ linux:誰能給我解釋下虛擬地址和物理地址的聯系
這個問題很大。。。。我盡自己所能給你解釋一下吧,如果你不能完全看懂,以後可以回頭再翻翻來看。關於虛擬內存的事情,大概是這樣的:
首先你要明確什麼是虛擬內存。虛擬內存實際上是操作系統對於內存管理的一種方式,比如說,對每個程序而言,它的內存編址都從0x00到0xff,但是實際上,這些內存對應的物理地址,應用程序本身是無法知道的,在這里就可以理解成操作系統對內存管理的一層抽象。
比如,可能進程init的虛擬地址0x00對應了物理地址的0x10,而kthreadd的虛擬地址0x00對應物理地址0x20,etc.
而且虛擬內存也是一種有效的進程間隔離的方式,極大的提升了進程的安全性和操作系統的穩定性,也就是我一個進程不管做什麼,都是在它自己的地址空間里做的,不會影響到其他進程和OS。
當然這是理想情況,實際上還有進程間通信啦之類,這就不在這個問題的范圍之內了。
而具體怎麼把這些虛擬地址對應到物理地址上,這是操作系統做的事情,估計這個也就是你的問題。
----以上是背景1-----
然後我要明確一下:地址匯流排4位的意思是說內存用4個bit位來表達地址,所以能夠index的地址位就是2^0-2^4,也就是0x0到0xf,就是16個bit的內存空間。
然後我們再來細化一下你的例子,就比方說在你的16bit的內存的機器上有1個OS,上面跑著2個程序。一般來說OS會保留地址的高位,比如11-15bit的位置,作為kernel space;然後0-10bit是user space。
在以上的前提下,虛擬內存的效果是:在每一個程序看來,這個程序都有0x0到0xf的地址可以用,並且它們的0xb-0xf都是shared kernel space,然後0x0-0xa都是自己的user space,這樣彷彿就有了32個bit的地址一樣。這就是你所謂的是用虛擬地址可以使總的地址操作物理地址。至於os是怎麼做到這點的,繼續往下看。
-----以上是背景2-----
操作系統對每一個進程有一個進程式控制制塊,叫PCB,Process Control Block,里邊存儲了每一個進程的進程信息,比如說寄存器,file descriptor,還有我們最關心的內存映射信息。每一個進程有一個遞增的id號,叫pid,也就是Process IDentifier.
-----以上是背景3-----
進程間切換,也就是說,比如說你一個系統只有1個CPU,但是有兩個進程要跑,而且要讓我們看起來好像是兩個進程同時在跑一樣。為什麼我要提到這個呢,後面繼續看。
-----以上是背景4-----
好,現在來講如何把虛擬地址映射到物理地址。從程序的角度來看,從malloc開始講起,比如,在某一時刻,一個進程調用了malloc,在堆(heap)上申請了2bits的空間。實際上這個行為的流程是,程序調用malloc,進入內核模式之後,調用mmap,如果成功,操作系統會從物理地址上取一塊2bits的內存,交給應用程序編入虛擬地址空間。更詳細一點說,每個進程對內存管理是一個紅黑樹的結構,也就是說,在每一個進程的PCB,里維護了一顆紅黑樹,然後動態的將所有的新分配的內存加到這個紅黑樹里邊,以保證程序對每一塊內存的訪問時間是差不多的。然後不知道你們教材中有沒有提到頁表(page table),頁表也是PCB中的一項,你們教材中應該會對頁表有詳細的講解,將如何對內存的地址進行換算,之類的。然後你要明確,頁表實際上是紅黑樹的cache,這樣可以加速程序對於常用的內存的訪問速度。
以上是操作系統對內存管理的一個大致概括,就是一塊物理的內存如何映射成為一塊虛擬的內存。
我在背景2中說,兩個程序都看到自己有16個bit的虛擬地址,總共有32bit,但是實際上硬體只有16bits,也就是說,不管你在紅黑樹和頁表中怎麼映射,一定會有沖突發生,比如,可能物理地址的0x02對應了進程1中的0x04,又在進程2的PCB中映射到了pid2的虛擬地址位0x06上。操作系統如何解決這個矛盾呢,首先在進程pid 1運行的時候,這個0x02對應的是pid1中的0x04;然後這個時候進程切換發生了,pid 2開始運行。當pid2需要用到它的0x04時,os發現0x02這個地址在pid1中也有映射,於是它就把0x02這個地址上的內容存到硬碟上的一個叫swap的空間內,然後把這個地址交給pid2使用。這樣就達到了擴大虛擬地址的效果。
但是這樣做是有代價的,因為一旦這個page被swap出去,那麼在pid1再來調用的時候會發生一系列的miss,從L1 cache miss到 L2 cache miss到L3 cache miss,然後頁表miss,memory miss,會對程序的性能造成極大的影響。影響有多大呢,平均來說:
L1 cache hit: 0.5ns
L2 cache hit: 7ns
主內存引用:100ns
順序從內存中讀取1MB:250,000ns
硬碟尋道:10,000,000ns
從硬碟上順序讀取1MB:30,000,000ns
所以你就可以知道這種行為是以極大的性能為代價的。
----講完啦-----
總的來說這個很大的話題,我剛才所寫的東西的就是試圖讓你對虛擬內存這個東西有一個基本的概念,然後大致的了解內存是如何映射的。就我現在能想到的,對這個虛擬內存話題的討論還包括多級頁表,進程間隔離&通信以及memory fragment。
個人水平有限,如果以上有什麼地方說錯的或者遺漏的,還請各位多多補充和批評,謝謝。
❷ Linux Kernel 2.4 和 2.6 的區別
1、 使用新的入口
必須包含 <linux/init.h>
mole_init(your_init_func);
mole_exit(your_exit_func);
老版本:int init_mole(void);
void cleanup_mole(voi);
2.4中兩種都可以用,對如後面的入口函數不必要顯示包含任何頭文件。
2、 GPL
MODULE_LICENSE("Dual BSD/GPL");
老版本:MODULE_LICENSE("GPL");
3、 模塊參數
必須顯式包含<linux/moleparam.h>
mole_param(name, type, perm);
mole_param_named(name, value, type, perm);
參數定義
mole_param_string(name, string, len, perm);
mole_param_array(name, type, num, perm);
老版本:MODULE_PARM(variable,type);
MODULE_PARM_DESC(variable,type);
4、 模塊別名
MODULE_ALIAS("alias-name");
這是新增的,在老版本中需在/etc/moles.conf配置,現在在代碼中就可以實現。
5、 模塊計數
int try_mole_get(&mole);
mole_put();
老版本:MOD_INC_USE_COUNT 和 MOD_DEC_USE_COUNT
6、 符號導出
只有顯示的導出符號才能被其他 模塊使用,默認不導出所有的符號,不必使用EXPORT_NO
_SYMBOLS
老闆本:默認導出所有的符號,除非使用EXPORT_NO_SYMBOLS
7、 內核版本檢查
需要在多個文件中包含<linux/mole.h>時,不必定義__NO_VERSION__
老版本:在多個文件中包含<linux/mole.h>時,除在主文件外的其他文件中必須定義_
_NO_VERSION__,防止版本重復定義。
8、 設備號
kdev_t被廢除不可用,新的dev_t拓展到了32位,12位主設備號,20位次設備號。
unsigned int iminor(struct inode *inode);
unsigned int imajor(struct inode *inode);
老版本:8位主設備號,8位次設備號
int MAJOR(kdev_t dev);
int MINOR(kdev_t dev);
9、 內存分配頭文件變更
所有的內存分配函數包含在頭文件<linux/slab.h>,而原來的<linux/malloc.h>不存在
老版本:內存分配函數包含在頭文件<linux/malloc.h>
10、 結構體的初試化
gcc開始採用ANSI C的struct結構體的初始化形式:
static struct some_structure = {
.field1 = value,
.field2 = value,
..
};
老版本:非標準的初試化形式
static struct some_structure = {
field1: value,
field2: value,
..
};
11、 用戶模式幫助器
int call_usermodehelper(char *path, char **argv, char **envp,
int wait);
新增wait參數
12、 request_mole()
request_mole("foo-device-%d", number);
老版本:
char mole_name[32];
printf(mole_name, "foo-device-%d", number);
request_mole(mole_name);
13、 dev_t引發的字元設備的變化
1、取主次設備號為
unsigned iminor(struct inode *inode);
unsigned imajor(struct inode *inode);
2、老的register_chrdev()用法沒變,保持向後兼容,但不能訪問設備號大於256的設備
。
3、新的介面為
a)注冊字元設備范圍
int register_chrdev_region(dev_t from, unsigned count, char *name);
b)動態申請主設備號
int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, char
*name);
看了這兩個函數郁悶吧^_^!怎麼和file_operations結構聯系起來啊?別急!
c)包含 <linux/cdev.h>,利用struct cdev和file_operations連接
struct cdev *cdev_alloc(void);
void cdev_init(struct cdev *cdev, struct file_operations *fops);
int cdev_add(struct cdev *cdev, dev_t dev, unsigned count);
(分別為,申請cdev結構,和fops連接,將設備加入到系統中!好復雜啊!)
d)void cdev_del(struct cdev *cdev);
只有在cdev_add執行成功才可運行。
e)輔助函數
kobject_put(&cdev->kobj);
struct kobject *cdev_get(struct cdev *cdev);
void cdev_put(struct cdev *cdev);
這一部分變化和新增的/sys/dev有一定的關聯。
14、 新增對/proc的訪問操作
<linux/seq_file.h>
以前的/proc中只能得到string, seq_file操作能得到如long等多種數據。
相關函數:
static struct seq_operations 必須實現這個類似file_operations得數據中得各個成
員函數。
seq_printf();
int seq_putc(struct seq_file *m, char c);
int seq_puts(struct seq_file *m, const char *s);
int seq_escape(struct seq_file *m, const char *s, const char *esc);
int seq_path(struct seq_file *m, struct vfsmount *mnt,
struct dentry *dentry, char *esc);
seq_open(file, &ct_seq_ops);
等等
15、 底層內存分配
1、<linux/malloc.h>頭文件改為<linux/slab.h>
2、分配標志GFP_BUFFER被取消,取而代之的是GFP_NOIO 和 GFP_NOFS
3、新增__GFP_REPEAT,__GFP_NOFAIL,__GFP_NORETRY分配標志
4、頁面分配函數alloc_pages(),get_free_page()被包含在<linux/gfp.h>中
5、對NUMA系統新增了幾個函數:
a) struct page *alloc_pages_node(int node_id,
unsigned int gfp_mask,
unsigned int order);
b) void free_hot_page(struct page *page);
c) void free_cold_page(struct page *page);
6、 新增Memory pools
<linux/mempool.h>
mempool_t *mempool_create(int min_nr,
mempool_alloc_t *alloc_fn,
mempool_free_t *free_fn,
void *pool_data);
void *mempool_alloc(mempool_t *pool, int gfp_mask);
void mempool_free(void *element, mempool_t *pool);
int mempool_resize(mempool_t *pool, int new_min_nr, int gfp_mask);
16、 per-CPU變數
get_cpu_var();
put_cpu_var();
void *alloc_percpu(type);
void free_percpu(const void *);
per_cpu_ptr(void *ptr, int cpu)
get_cpu_ptr(ptr)
put_cpu_ptr(ptr)
老版本使用
DEFINE_PER_CPU(type, name);
EXPORT_PER_CPU_SYMBOL(name);
EXPORT_PER_CPU_SYMBOL_GPL(name);
DECLARE_PER_CPU(type, name);
DEFINE_PER_CPU(int, mypcint);
2.6內核採用了可剝奪得調度方式這些宏都不安全。
17、 內核時間變化
1、現在的各個平台的HZ為
Alpha: 1024/1200; ARM : 100/128/200/1000; CRIS: 100; i386: 1000; IA-64:
1024; M68K: 100; M68K-nommu: 50-1000; MIPS: 100/128/1000; MIPS64: 100;
PA-RISC: 100/1000; PowerPC32: 100; PowerPC64: 1000; S/390: 100; SPARC32:
100; SPARC64: 100; SuperH: 100/1000; UML: 100; v850: 24-100; x86-64: 1000.
2、由於HZ的變化,原來的jiffies計數器很快就溢出了,引入了新的計數器jiffies_64
3、#include <linux/jiffies.h>
u64 my_time = get_jiffies_64();
4、新的時間結構增加了納秒成員變數
struct timespec current_kernel_time(void);
5、他的timer函數沒變,新增
void add_timer_on(struct timer_list *timer, int cpu);
6、新增納秒級延時函數
ndelay();
7、POSIX clocks 參考kernel/posix-timers.c
18、 工作隊列(workqueue)
1、任務隊列(task queue )介面函數都被取消,新增了workqueue介面函數
struct workqueue_struct *create_workqueue(const char *name);
DECLARE_WORK(name, void (*function)(void *), void *data);
INIT_WORK(struct work_struct *work,
void (*function)(void *), void *data);
PREPARE_WORK(struct work_struct *work,
void (*function)(void *), void *data);
2、申明struct work_struct結構
int queue_work(struct workqueue_struct *queue,
struct work_struct *work);
int queue_delayed_work(struct workqueue_struct *queue,
struct work_struct *work,
unsigned long delay);
int cancel_delayed_work(struct work_struct *work);
void flush_workqueue(struct workqueue_struct *queue);
void destroy_workqueue(struct workqueue_struct *queue);
int schele_work(struct work_struct *work);
int schele_delayed_work(struct work_struct *work, unsigned long
delay);
19、 新增創建VFS的"libfs"
libfs給創建一個新的文件系統提供了大量的API.
主要是對struct file_system_type的實現。
參考源代碼:
drivers/hotplug/pci_hotplug_core.c
drivers/usb/core/inode.c
drivers/oprofile/oprofilefs.c
fs/ramfs/inode.c
fs/nfsd/nfsctl.c (simple_fill_super() example)
❸ 線程鎖里malloc線程鎖linux
c語言雙線程鎖的例子?
在Linux使用C語言編輯程序使用互斥鎖實現兩個線程之間同步,一個線程負責從標准輸入設備中讀取數據,而另一個線程則負責將讀入的數據輸出到標准輸出設備上,當輸入「end」時結束該程序。
thread線程可以在linux上用嗎?
thread線程是可以在linux上使用的,支持多線程運行。
linux如何停止線程?
殺死線程所在的進程就可以,psaux|grep進程名kill-TERM進程號如果你指的寫程序,那就參考manpthread_exit。
《Linux就該這么學》里有相關介紹,建議看看。
linux有沒有線程id確認函數?
linuxC中,獲取當前進程id函數為getpid();頭文件:#include?函數原型:pid_t?getpid(void);函數說明:getpid?()用來取得目前進程的進程id,許多程序利用取到的此值來建立臨時文件,?以避免臨時文件相同帶來的問題。返回值:目前進程的進程id範例#include?#include?main(){????printf(pid=%dn,?getpid());}執行:pid=1494?/*每次執行結果都不一定相同?*/
linux下如何實現兩個內核線程之間的通信?
線程間通信就是通過全局變數啊,線程之間沒有「通信」的說法吧,不管有幾個線程,它們都是在同一個進程地址空間內,都共享同樣的內存空間,所以「通信」的說法才多見於進程之間,因為不同的進程才是不同的內存地址空間。進程內的變數每個線程都是可以訪問的,是共享的,但是線程之間沒有固定的執行順序,為避免時序上的不同步問題,所以線程之間才會需要同步機制。線程之間的重點就是同步機制。
❹ malloc函數頭文件用哪個有的寫malloc.h ,有的寫stdlib.h ,還有的寫alloc.h 。。。。
簡單來說, 在Microsoft Visual C++環境下,malloc.h和stdlib.h中都包含了對malloc函數的聲明,所以包含任何一個都可以調用malloc函數;而alloc.h是Borland C++環境下的頭文件,也是Linux/Unix環境下進行C語言開發的頭文件,所以在這些環境下調用malloc函數要包含alloc.h。
❺ 如何在自己的程序中替換linux標准庫函數
#include <stdio.h>
#include <string.h>
#include <malloc.h>
// 將strRes中的t替換為s,替換成功返回1,否則返回0。
int StrReplace(char strRes[],char from[], char to[]) {
int i,flag = 0;
char *p,*q,*ts;
for(i = 0; strRes[i]; ++i) {
if(strRes[i] == from[0]) {
p = strRes + i;
q = from;
while(*q && (*p++ == *q++));
if(*q == '\0') {
ts = (char *)malloc(strlen(strRes) + 1);
strcpy(ts,p);
strRes[i] = '\0';
strcat(strRes,to);
strcat(strRes,ts);
free(ts);
flag = 1;
}
}
}
return flag;
}
int main() {
char str[80] = "098123asd098opu";
printf("替換前:%s\n",str);
if(StrReplace(str,"098","33210")) printf("替換後:%s\n",str);
else printf("沒有任何替換。\n");
return 0;
}
❻ 在C++中引用malloc的頭文件是什麼》
Linux版:
malloc(配置內存空間)
相關函數 calloc,free,realloc,brk
表頭文件 #include<stdlib.h>
定義函數 void * malloc(size_t size);
函數說明 malloc()用來配置內存空間,其大小由指定的size決定。
返回值 若配置成功則返回一指針,失敗則返回NULL。
範例 void p = malloc(1024); /*配置1k的內存*/
其它版的也相差不多