Rob Pike 用地鼠燒書做例子:
如果今天增加多一只地鼠,一個推車或多一個焚燒盧,這樣有機會作到更好的資源使用率,但我們不能保證兩只或更多地鼠會同時進行 (可能只有有限的火爐)。在單核系統中只能允許一次進行一次的燒書工作,那樣就沒有效率了。 以 Concurrency 的方式去作業,能夠以不同的解構方式去進行,可以是三個地鼠分別負責一部分的工作 (decomposition) 其中也可以 Parallelism: 或
Concurrency: 是指程式架構,將程式拆開成多個可獨立運作的工作,像是驅動程式都可獨立運作,但不需要平行化
Parallelism: 是指程式執行,同時執行多個程式。Concurrency 可能會用到 parallelism,但不一定要用 parallelism 才能實現 concurrency。eg:Vector dot product
線上教材 Introduction to OpenMP 做了以下整理:
(1) Concurrent (並行)
(2) Parallel (平行)
Solaris Green Threads
、GNU Portable Threads
Windows NT/XP/2000
、Linux
、Solaris 9 and later
Windows NT/2000 with the ThreadFiber package
IRIX
、HP-UX
、Tru64 UNIX
、Solaris 8 and earlier
#include <pthread.h>
int pthread_create(pthread_t *thread, pthread_attr_t
*attr, void *(*start_routine)(void *), void *arg);
//create a thread
void pthread_exit(void *retval);
//terminate a thread
int pthread_join(pthread_t th, void **thread_return);
//wait for thread termination
int pthread_create(pthread_t *thread,
pthread_attr_t *attr, void *(*start_routine)(void
*), void *arg);
pthread_t *thread
:thread 的識別字pthread_attr_t *attr
:thread 的屬性,設定為 NULL 表示使用預設值void *(*start_routine)(void*)
:thread 要執行的 functionvoid *arg
:傳遞給 thread 的參數void pthread_exit(void *retval);
void *retval
:thread 結束時回傳的變數int pthread_join(pthread_t th, void **thread_return);
pthread_t th
:thread 識別字void **thread_return
:接收 pthread_exit 傳回的變數#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>
#include <time.h>
#define NUM_THREADS 10
#define MSIZE 10000
// 找出 1 - 10000 的所有質數
static double getDoubleTime();
void *thread_function(void *arg);
pthread_mutex_t work_mutex;
// 宣告 prime_array 陣列
int prime_array[NUM_THREADS][(MSIZE / NUM_THREADS)];
int main(void) {
int res;
pthread_t a_thread[NUM_THREADS];
void *thread_result;
int lots_of_threads;
int print_prime = 0;
// start to measure time...
double start_time = getDoubleTime();
// initialize mutex...
res = pthread_mutex_init(&work_mutex, NULL);
if (res != 0) {
perror("Mutex initialization failed");
exit(EXIT_FAILURE);
}
// pthread_create...
for (lots_of_threads = 0; lots_of_threads < NUM_THREADS; lots_of_threads ++) {
res = pthread_create(&(a_thread[lots_of_threads]), NULL, thread_function, (void*)(long)lots_of_threads);
if (res != 0) {
perror("Thread creation failed");
exit(EXIT_FAILURE);
}
}
// pthread_join...
for (lots_of_threads = NUM_THREADS - 1; lots_of_threads >= 0; lots_of_threads--) {
res = pthread_join(a_thread[lots_of_threads], &thread_result);
if (res != 0) {
perror("pthread_join failed");
}
}
int i = 0; // 設定計數器
for (lots_of_threads = 0; lots_of_threads < NUM_THREADS; lots_of_threads ++) {
printf("\n\nThe thread[%d]'s numbers:\n", lots_of_threads);
for (i = 0; i < (MSIZE / NUM_THREADS); i++) {
if (prime_array[lots_of_threads][i] != 0)
printf("%d\t", prime_array[lots_of_threads][i]); }
}
printf("\nThread joined\n");
// stop measuring time...
double finish_time = getDoubleTime();
printf("Execute Time: %.3lf ms\n", (finish_time - start_time));
exit(EXIT_SUCCESS);
}
void *thread_function(void *arg) {
// pthread_mutex_lock(&work_mutex);
int my_num = (long)arg;
// if (MSIZE % NUM_THREADS != 0){ printf("error"); pthread_exit(-1); }
int start_num = (MSIZE / NUM_THREADS) * my_num + 1;
int end_num = (MSIZE / NUM_THREADS) * (my_num + 1);
int i = 0, j = 0, k = 0; // Set the loop
int count = 0; // Set the counter
int result = 0; // result
printf("I'm thread[%d], start_num:%d, end_num:%d\n", my_num, start_num, end_num);
/* find the prime number */
for (i = start_num; i <= end_num; i++) {
count = 0; // Reset counter
for (j = 1; j <= i; j++) {
if (i % j == 0)
count += 1;
}
if (count == 2) {
prime_array[my_num][k] = i;
k++;
}
}
// pthread_mutex_unlock(&work_mutex);
pthread_exit(0);
}
static double getDoubleTime() {
struct timeval tm_tv;
gettimeofday(&tm_tv,0);
return (double)(((double)tm_tv.tv_sec * (double)1000. + (double)(tm_tv.tv_usec)) * (double)0.001);
}
#include <stdlib.h>
#include <stdio.h>
int main(void) {
int i = 0, j = 0; // Set loop
float mf[7], tmp = .0, input = .0, sa = .0, ua = .0, ub = .0;
char name[7][3] = {"NB", "NM", "NS", "ZR", "PS", "PM", "PB"};
/* Key the value of name */
printf("Please define NS、NM、NB value (smaller than 0)\n");
for (i = 0; i < 3; i++) {
scanf("%f", &mf[i]);
}
printf("Please define PS、PM、PB value (bigger than 0)\n");
for (i = 3; i < 6; i++) {
scanf("%f", &mf[i]);
}
mf[6] = 0; // Set the ZR value
/* Sort the numbers */
for (i = 0; i < 7; i++) {
for (j = 0; j < 7; j++) {
if ((mf[j] > mf[i])) {
tmp = mf[i];
mf[i] = mf[j];
mf[j] = tmp;
}
}
}
/* The entry */
while(1) {
/* Key the value of x */
printf("\n\nPlease key in the value of 'Input'\n");
printf("Input = ");
scanf("%f", &input);
/* Calculate the linear μ */
printf("\n\n****The membership function****\n");
for (i = 0; i < 7; i++) {
// input = mf
if (((input == mf[i]))) {
printf("μ[%s] = %.f\n", name[i], (mf[i] / mf[i]));
break;
}
// input bigger than the max's mf
else if ((input > mf[6])) {
printf("μ[%s] = %.f\n", name[6], (mf[6] / mf[6]));
break;
}
// input smaller than the min's mf
else if ((input < mf[0])) {
printf("μ[%s] = %.f\n", name[0], (mf[0] / mf[0]));
break;
}
// Calculate...
else if ((input > mf[i]) && (input < mf[i+1])) {
/* linear area */
printf("\n****The linear****\n");
ua = (1 - (mf[i] - input) / (mf[i] - mf[i+1]));
ub = (1 - (input - mf[i+1]) / (mf[i] - mf[i+1]));
printf("μ[%s] = %.3f\n", name[i], ua);
printf("μ[%s] = %.3f\n", name[i+1], ub);
/* non-linear area */
printf("\n****The non-linear (S-function)****\n");
if (input < ((mf[i] + mf[i+1]) / 2)) {
sa = (((input - mf[i]) / (mf[i+1] - mf[i])));
ua = 1 - (2 * sa * sa);
ub = 1 - ua;
printf("μ[%s] = %.3f\n", name[i], ua);
printf("μ[%s] = %.3f\n", name[i+1], ub);
}
else if ((input >= ((mf[i] + mf[i+1]) / 2)) && (input < mf[i+1])) {
sa = (((input - mf[i+1]) / (mf[i+1] - mf[i])));
ua = (2 * sa * sa);
ub = 1 - ua;
printf("μ[%s] = %.3f\n", name[i], ua);
printf("μ[%s] = %.3f\n", name[i+1], ub);
}
break;
}
}
}
return 0;
}
從 1 - 100 之間取出所有的質數,利用 threads 來分配計算質數的範圍。
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>
#include <time.h>
#define NUM_THREADS 10
#define MSIZE 100
// 找出 1 - 100 的所有質數
static double getDoubleTime();
void *thread_function(void *arg);
pthread_mutex_t work_mutex;
int main(void) {
int res;
pthread_t a_thread[NUM_THREADS];
void *thread_result;
int lots_of_threads;
// start to measure time...
double start_time = getDoubleTime();
// initialize mutex...
res = pthread_mutex_init(&work_mutex, NULL);
if (res != 0) {
perror("Mutex initialization failed");
exit(EXIT_FAILURE);
}
// pthread_create...
for (lots_of_threads = 0; lots_of_threads < NUM_THREADS; lots_of_threads ++) {
res = pthread_create(&(a_thread[lots_of_threads]), NULL, thread_function, (void*)(long)lots_of_threads);
if (res != 0) {
perror("Thread creation failed");
exit(EXIT_FAILURE);
}
}
// pthread_join...
for (lots_of_threads = NUM_THREADS - 1; lots_of_threads >= 0; lots_of_threads--) {
res = pthread_join(a_thread[lots_of_threads], &thread_result);
if (res != 0) {
perror("pthread_join failed");
}
}
printf("\nThread joined\n");
// stop measuring time...
double finish_time = getDoubleTime();
printf("Execute Time: %.3lf ms\n", (finish_time - start_time));
exit(EXIT_SUCCESS);
}
void *thread_function(void *arg) {
// pthread_mutex_lock(&work_mutex);
int my_num = (long)arg;
// if (MSIZE % NUM_THREADS != 0){ printf("error"); pthread_exit(-1); }
int start_num = (MSIZE / NUM_THREADS) * my_num + 1;
int end_num = (MSIZE / NUM_THREADS) * (my_num + 1);
int i = 0, j = 0; // Set the loop
int count = 0; // Set the counter
int result = 0; // result
printf("\n\nI'm thread[%d], start_num:%d, end_num:%d\n", my_num, start_num, end_num);
/* find the prime number */
for (i = start_num; i <= end_num; i++) {
count = 0; // Reset counter
for (j = 1; j <= i; j++) {
if (i % j == 0)
count += 1;
}
if (count == 2) {
result = i;
printf("%d\t", result);
}
}
// pthread_mutex_unlock(&work_mutex);
pthread_exit(0);
}
static double getDoubleTime() {
struct timeval tm_tv;
gettimeofday(&tm_tv,0);
return (double)(((double)tm_tv.tv_sec * (double)1000. + (double)(tm_tv.tv_usec)) * (double)0.001);
}
當ㄧ個 thread 還沒 printf 完它所負責範圍的質數時,就被切換到另一個 thread 裡面執行。
/* 前面省略 */
/* find the prime number */
for (i = start_num; i <= end_num; i++) {
count = 0; // Reset counter
for (j = 1; j <= i; j++) {
if (i % j == 0)
count += 1;
}
if (count == 2) {
result = i;
printf("%d-[%d]\t", result, my_num);
}
}
/* 後面省略 */
[執行結果]
看來前面的假設是正確的,但是我們該如何避免這種情形?
這一陣子開始使用 Vim 作為主要的文字編輯器,但是在使用上遇到了一些問題 (主要原因是還不習慣 Vim 的操作方式),因此整理了一些常用的技巧。
刪除一行 - dd
進入編輯模式 - i
進入VISUAL模式 - v
進入VISUAL BLOCK模式 - ctrl
(按鍵) + v
寫入(儲存) - :w
離開 - :q
不儲存強制離開 - :q!
paste模式,直接貼上文字時格式不會跑掉 - :set paste
顯示行數 - :set nu
設定一個tab等於四個空白長度 - :set tabstop=4
設定以後,使用tab鍵時會用空白取代(由tabstop決定) - :set expandtab
消除Highlight - :noh
範圍縮排(3到5行向右縮排,向左縮排用<) - :3,5>
將tab轉換成space - :retab
將檔案編碼轉成utf8 - :set fileencoding=utf8
另存新檔 - :w myfilename
開啟檔案 - :e filename
自動對齊 - ==
移動到該行最前端 - ^
移動到該行最末端 - $
移動到下一個單字的第一個字元 - w
移動到前一個單字的第一個字元 - b
移動到下一個單字的最後一個字元 - e
移動到下一個單字的最後一個字元(無視符號) - E
全選(gg為游標移動到最上方,v為切換成選擇模式,G是游標移動到最下方) - ggvG
游標移動到特定行數(移動到第三行) - 3G
複製反白的區塊(需要在VISUAL模式) - y
剪下反白的區塊(需要在VISUAL模式) - d
複製游標所在的那行(需要在VISUAL模式) - shift
(按鍵) + y
貼上 - p
回復 - u
自動完成 (需要在編輯模式) - ctrl
(按鍵) + p
搜尋字串 - /<字串>
:向下找、?<字串>
:向上找