簡體   English   中英

為什么頁面錯誤不會導致線程稍后完成其執行?

[英]Why does the page fault not cause the thread to finish its execution later?

我有下面的代碼,我故意在file.c中的一個線程中創建頁面錯誤

util.c

#include "util.h"

// to use as a fence() instruction
extern inline __attribute__((always_inline))
CYCLES rdtscp(void) {
    CYCLES cycles;
    asm volatile ("rdtscp" :  "=a" (cycles));

    return cycles;
}

// initialize address
void init_ram_address(char* FILE_NAME){
    char *filename = FILE_NAME;
    int fd = open(filename, O_RDWR);
    if(fd == -1) {
        printf("Could not open file .\n");
        exit(0);
    }
    void *file_address = mmap(NULL, DEFAULT_FILE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_POPULATE, fd, 0);
    ram_address = (int *) file_address;
}

// initialize address
void init_disk_address(char* FILE_NAME){
    char *filename = FILE_NAME;
    int fd = open(filename, O_RDWR);
    if(fd == -1) {
        printf("Could not open file .\n");
        exit(0);
    }
    void *file_address = mmap(NULL, DEFAULT_FILE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    disk_address = (int *) file_address;
}

file.c

#include "util.h"

void *f1();
void *f2();

pthread_barrier_t barrier;
pthread_mutex_t mutex;

int main(int argc, char **argv)
{
    pthread_t t1, t2;

    // in ram
    init_ram_address(RAM_FILE_NAME);
    // in disk
    init_disk_address(DISK_FILE_NAME);

    pthread_create(&t1, NULL, &f1, NULL);
    pthread_create(&t2, NULL, &f2, NULL);

    
    pthread_join(t1, NULL);
    pthread_join(t2, NULL);
    
    return 0;
}

void *f1()
{
    rdtscp();
    int load = *(ram_address);
    rdtscp();
    printf("Expecting this to be run first.\n");
}

void *f2()
{
    rdtscp();
    int load = *(disk_address);
    rdtscp();
    printf("Expecting this to be run second.\n");
}

我在上面的代碼中使用rdtscp()來進行隔離(以確保僅在加載操作完成后才執行打印語句)。

由於t2將導致頁面錯誤,我希望t1先完成其打印語句的執行。

為了在同一個內核上運行兩個線程,我運行taskset -c 10./file

我看到t2t1之前打印它的語句。 這可能是什么原因?

我認為您期望t2int load = *(disk_address); 導致上下文切換到t1 ,並且由於您將所有內容都固定到同一個 CPU 內核,這將使t1有時間贏得爭奪stdout的鎖定。

軟頁面錯誤不需要上下文切換,只需使用頁面緩存中的文件頁面更新頁表。 盡管映射由磁盤文件支持,而不是匿名 memory 或只是寫時復制技巧,但如果該文件最近已被讀取或寫入,它將在頁面緩存中很熱並且不需要 I/O(這將使頁錯誤)。

也許在測試運行之前嘗試驅逐磁盤緩存,比如使用echo 3 | sudo tee /proc/sys/vm/drop_caches echo 3 | sudo tee /proc/sys/vm/drop_caches如果這是 Linux,那么在沒有MAP_POPULATE的情況下訪問 mmap 區域將是一個頁面錯誤(需要 I/O)。

(請參閱 * https://unix.stackexchange.com/questions/17936/setting-proc-sys-vm-drop-caches-to-clear-cache*;如果是最近sync的話,至少在磁盤文件上同步寫的,以確保它的頁面是干凈的並且能夠被驅逐,也就是丟棄。)


您沒有顯示ram_addressdisk_address的聲明。 如果它不是volatile int *disk_address之類的指向volatile的指針,則可以在編譯時優化負載。 對像int load這樣的非轉義本地變量的寫入不必尊重"memory"破壞者,因為沒有其他東西可以引用它們。

如果您在沒有優化或其他東西的情況下進行編譯,那么即使沒有volatile ,負載仍然會發生。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM