contributed by <f5120125
>
sysprog
#if...#else...#endif
#ifdef MACRO_NAME...#endif
, #ifndef MACRO_NAME...#endif
#if defined( MACRO_NAME )...#endif
#include IMPL
pthread_create()
pthread_join()
pthread_exit()
mmap()
munmap()
phonebook_opt.h
中定義了一個macro: OPT
, 主要功能是拿來判斷main.c
中哪裡是原來版本或是執行緒版本該執行的
#if OPT
/*do sommthing*/
#endif
#ifdef OPT
/*do something*/
#endif
#if defined(OPT) && OPT
/*do something*/
#endif
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine)(void *), void *arg);
void *
為 generic pointer, 主要功用
void *somePtr;
int *integerPtr = 10;
int *anotherIntPtr;
somePtr = &integerPtr;/*儲存int型態的address*/
//error occur !!
printf("%d\n", (int)(*somPtr));/*不能使用`*`去存取值*/
anotherIntPtr = (int*)somePtr;/*typecast成(int*)型態*/
printf("%d\n", *anotherIntPtr);
(*start_routine)
為 function pointer, 其所能傳入的參數型態為 void *
int pthread_join(pthread_t thread, void **retval);
#include <sys/mman.h>
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
mmap() 將檔案映射到一個 virtual memory address 上面,藉由直接對 memory address 修改的方式不用經過buffer,減少資料load到緩衝區的overhead,快速的記憶體存取可以提高對檔案 IO 的效率
Blocking VS Non-blocking I/O
addr
: 要 map 到的記憶體位置
length
: 要 mapping 的長度,它會從 fd + offset 的位置開始 mapping 檔案。prot
: 要保護的記憶體保護 mappingflags
: 選擇 map file 能不能被其他程式看到
fd
: 用系統函式 open 打開的檔案位置,open mode 可以選擇檔案的讀寫屬性,不能跟 prot 有衝突。offset
: 從檔案的哪裡開始 mapping,offset 必須是 page size 的倍數,可以用 sysconf(_SC_PAGE_SIZE) 取得。munmap() 用來取消參數 start 所指的映射記憶體起始地址,參數 length 則是欲取消的記憶體大小。當行程結束或利用 exec 相關函數來執行其他程式時,映射記憶體會自動解除,但關閉對應的文件描述詞時不會解除映射。
#include <stdio.h>
#include <sys/stat.h>//stat, stat(paath, struct stat)
#include <sys/mman.h>//mmap()
#include <fcntl.h>//open(file_name, )
#include <stdbool.h>
#define MAX 16
#define ORIG_FILE_PATH "./dictionary/words.txt"
#define ALIGNMENT_FILE "align.txt"
off_t getFileSize( char *path);
int main(){
bool consistency=true;
char orig_buff[MAX];
char align_buff[MAX];
FILE *orig_fp = fopen(ORIG_FILE_PATH, "r");
FILE *align_fp = fopen(ALIGNMENT_FILE, "r");
int fd = open(ALIGNMENT_FILE, O_RDONLY | O_NONBLOCK);
off_t new_file_size = getFileSize(ALIGNMENT_FILE);
char *map = mmap(NULL, new_file_size, PROT_READ, MAP_SHARED, fd, 0);
char *tmp=map;
while( fgets(orig_buff, sizeof(orig_buff), orig_fp) ){
if( strncmp(orig_buff, tmp, sizeof(orig_buff)) != 0){
consistency=false;
break;
}
tmp+=MAX;
}
if(consistency)
printf("Files are consistent\n");
else
printf("Files are not the same\n");
return 0;
}
off_t getFileSize( char *path){
struct stat file_stat;
stat(path, &file_stat);
return file_stat.st_size;
}
Performance counter stats for './phonebook_opt' (100 runs):
841,854 cache-misses # 66.507 % of all cache refs ( +- 1.05% )
1,265,807 cache-references ( +- 0.65% )
172,850,372 instructions # 0.76 insns per cycle ( +- 0.07% )
226,345,721 cycles ( +- 0.88% )
0.090487839 seconds time elapsed ( +- 2.76% )
cc -Wall -std=gnu99 calculate.c -o calculate
./calculate
hua@hua-ubuntu:~/Desktop/sysprog-class/homework2/phonebook-concurrent$ ./check
Files are consistent
entry *etmp;
pHead = pHead->pNext;
for (int i = 0; i < THREAD_NUM; i++) {
if (i == 0) {
pHead = argsPtr[i]->entryHead->pNext;
} else {
etmp->pNext = argsPtr[i]->entryHead->pNext;
}
etmp = argsPtr[i]->entryTail;
}
Thread 缺陷
Thread Pool 功能
typedef struct {
void (*function)(void *);
void *argument;
} threadpool_task_t;
//Thread Pool 需要 job/task 讓 Thread 知道他們要做什麼事情
threadpool_t *threadpool_create(int thread_count, int queue_size, int flags);
//傳入 thread 的數量,queue 的大小,回傳 threadpool 型態是 threadpool_t
int threadpool_add(threadpool_t *pool, void (*routine)(void *), void *arg, int flags);
//傳入 threadpool,要執行的 function 位置,要傳入的參數
int threadpool_destroy(threadpool_t *pool, int flags);
//傳入 threadpool,會把 threadpool 的空間 free 掉
void *tpool_init(int num_threads)
//初始化時決定要用哪種方式進行 put work,選用 `ring-buffer` 的方式將 worker 加入queue
static int wait_for_thread_registration(int num_expected)
//確保所有執行緒都在準備中
int tpool_add_work(void *pool, void(*routine)(void *), void *arg)
//配合 `dispatch` 加入 task 到 work queue 中
static void *tpool_thread(void *arg)
//給 worker task,沒有用到 mutex_lock
static tpool_work_t *get_work_concurrently(thread_t *thread)
//利用 CAS 讓每個執行緒拿到自己的 task,確保從 work queue 出來時,遞減 `out` 的變數同步
void tpool_destroy(void *pool, int finish);
//判斷所有的 queue 是不是空的,確保所有 worker 完成工作
CAS
以具有 atomic 特性的計算操作來達成。
bool CAS(T* addr, T exp, T val)
{
if (*addr == exp) {
*addr = val;
return true;
}
return false;
}
$ git clone https://github.com/xhjcehust/LFTPool
$ cd LFTPool/
$ make
$ ./testtpool