包括 可執行的程序文本、程序全局內存、堆內存以及文件描述符數組
#include <unistd.h> #include <stdio.h> #include <pthread.h> void printid(const char* str) { pid_t pid = getpid(); pthread_t tid = pthread_self(); fprintf(stdout, "%s pid:%u,tid:%u\n", str, (unsigned int)pid, (unsigned int)tid); } void* thread_func(void* arg) { printid("new thread: "); return (void*)0; } int main(int argc, char* argv[]) { pthread_t tid; int ret = pthread_create(&tid, NULL, thread_func, NULL); if (ret != 0) { fprintf(stderr, "pthread_create error\n"); return -1; } printid("main thread: "); sleep(1); return 0; }
#include <pthread.h> #include <stdio.h> #include <unistd.h> #include <assert.h> #define NTHREADS 5 void* PrintHello(void* threadId) { int tid = ((int)threadId); fprintf(stdout, "Hello world, thread %d\n", tid); pthread_exit(NULL); } int main(int argc, char* argv[]) { pthread_t threads[NTHREADS]; int rc = 0; for (int i = 0; i < NTHREADS; ++i) { fprintf(stdout, "In main: creating thread %d\n", i); rc = pthread_create(&threads[i], NULL, PrintHello, (void*)i); if (rc != 0) { fprintf(stderr, "error:return code from pthread_create is %d\n", rc); exit(-1); } } pthread_exit(NULL); }
上述代碼,咱們建立了5個線程,每一個線程打印一條包含線程編號的語句安全
能夠預想到:每次運行程序時,結果不盡相同。由於 線程建立時並不能保證哪一個線程會先執行,不能在線程調度上作出任何假設數據結構
假如咱們將上述代碼中
多線程
rc = pthread_create(&threads[i], NULL, PrintHello, (void*)i);
void* PrintHello(void* threadId) { int tid = ((int)threadId); fprintf(stdout, "Hello world, thread %d\n", tid); pthread_exit(NULL); }
改成如下:併發
rc = pthread_create(&threads[i], NULL, PrintHello, (void*)&i);
void* PrintHello(void* threadId) { int tid = *((int*)threadId); fprintf(stdout, "Hello world, thread %d\n", tid); pthread_exit(NULL); }
僅有的差異就是線程執行函數的參數傳遞不一樣,執行改過以後的程序:函數
咱們能夠看到程序執行結果徹底不一樣而且不正確性能
對於修改前:直接傳遞 變量i 的值,這是值語義,以後線程操做的只是 變量i 的副本,跟原來的 變量i 沒有任何關係,沒有競爭出現spa
對於修改後:傳遞的是 變量i 的地址(地址),這是引用語義,以後線程操做的是 原變量i,這時多個線程就出現了競爭,操作系統
由於這時 變量i 的地址是共享內存,對全部線程可見,其他5個線程經過共享內存在讀這個變量i,而主線程經過 i++在寫這個變量值線程
這之間並無任何同步,因此5個線程讀取的值並不正確
#include <stdio.h> #include <unistd.h> #include <pthread.h> #include <stdlib.h> #include <assert.h> #include <math.h> #define NTHREADS 5 void* busywork(void* ptr) { int tid = (int)ptr; fprintf(stdout, "Thread %d starting...\n", tid); double result = 0.0; for (int i = 0; i < 1000000; ++i) { result = result + sin(i) * tan(i); } fprintf(stdout, "Thread %d done. Result = %e\n", tid, result); pthread_exit((void*)ptr); } int main(int argc, char* argv[]) { pthread_t thread[NTHREADS]; pthread_attr_t attr; /* Initialize and set thread detached attribute */ pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); for (int i = 0; i < NTHREADS; ++i) { fprintf(stdout, "Main: creating thread %d\n", i); int rc = pthread_create(&thread[i], &attr, busywork, (void*)i); if (rc != 0) { fprintf(stderr, "error:return code from pthread_create is %d\n", rc); exit(-1); } } /* Free attribute and wait for the other threads */ void* status; pthread_attr_destroy(&attr); for (int i = 0; i < NTHREADS; ++i) { int rc = pthread_join(thread[i], &status); if (rc != 0) { fprintf(stderr, "error:return code from pthread_join id %d\n", rc); exit(-1); } fprintf(stdout, "Main:completed join with thread %d having a status of %d\n", i, (int)status); } fprintf(stdout, "Main: program completed. Exiting\n"); pthread_exit(NULL); }
爲了解決這個問題,線程必須使用鎖,在同一時間只容許一個線程訪問該變量
#include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <pthread.h> struct foo { int f_count; pthread_t f_lock; /* more stuff here... */ }; struct foo* foo_alloc(void) { struct foo* fp = malloc(sizeof(struct foo)); if (fp != NULL) { fp->f_count = 1; int ret = pthread_mutex_init(&fp->f_lock, NULL); if (ret != 0) { free(fp); return NULL; } } return fp; } /* increase a reference to the object */ void foo_increase(struct foo* fp) { assert(fp != NULL); pthread_mutex_lock(&fp->f_lock); fp->f_count++; pthread_mutex_unlock(&fp->f_lock); } /* decrease a reference to the object */ void foo_decrease(struct foo* fp) { assert(fp != NULL); pthread_mutex_lock(&fp->f_lock); if (--fp->f_count == 0) { pthread_mutex_unlock(&fp->f_lock); pthread_mutex_destroy(&fp->f_lock); free(fp); } else { pthread_mutex_unlock(&fp->f_lock); } }
1 #include <unistd.h> 2 #include <stdio.h> 3 #include <stdlib.h> 4 #include <assert.h> 5 #include <pthread.h> 6 7 #define NHASH 29 8 #define HASH(fp) (((unsigned long)(fp)) % NHASH) 9 10 pthread_mutex_t hashlock = PTHREAD_MUTEX_INITIALIZER; 11 12 struct foo { 13 struct foo* f_next; 14 int f_count; 15 pthread_mutex_t f_lock; 16 int f_id; 17 /* more stuff here... */ 18 }; 19 20 struct foo* fh[NHASH]; 21 22 struct foo* foo_alloc(void) 23 { 24 struct foo* fp = malloc(sizeof(struct foo)); 25 if (fp != NULL) { 26 fp->f_count = 1; 27 int ret = pthread_mutex_init(&fp->f_lock, NULL); 28 if (ret != 0) { 29 free(fp); 30 return NULL; 31 } 32 int idx = HASH(fp); 33 pthread_mutex_lock(&hashlock); 34 fp->f_next = fh[idx]; 35 fh[idx] = fp->f_next; 36 pthread_mutex_lock(&fp->f_lock); 37 pthread_mutex_unlock(&hashlock); 38 39 /* continue initialization...... */ 40 pthread_mutex_unlock(&fp->f_lock); 41 } 42 return fp; 43 } 44 45 /* increase a reference to the object */ 46 void foo_increase(struct foo* fp) 47 { 48 assert(fp != NULL); 49 pthread_mutex_lock(&fp->f_lock); 50 fp->f_count++; 51 pthread_mutex_unlock(&fp->f_lock); 52 } 53 54 /* find an existing object */ 55 struct foo* foo_find(int id) 56 { 57 struct foo* fp; 58 int idx = HASH(fp); 59 pthread_mutex_lock(&hashlock); 60 for (fp = fh[idx]; fp != NULL; fp = fp->f_next) { 61 if (fp->f_id == id) { 62 foo_increase(fp); 63 break; 64 } 65 } 66 pthread_mutex_unlock(&hashlock); 67 return fp; 68 } 69 70 /* decrease a reference to the object */ 71 void foo_decrease(struct foo* fp) 72 { 73 assert(fp != NULL); 74 struct foo* tfp = NULL; 75 int idx = 0; 76 pthread_mutex_lock(&fp->f_lock); 77 if (fp->f_count == 1) { 78 pthread_mutex_unlock(&fp->f_lock); 79 pthread_mutex_lock(&hashlock); 80 pthread_mutex_lock(&fp->f_lock); 81 /* need to recheck the condition */ 82 if (fp->f_count != 1) { 83 fp->f_count--; 84 pthread_mutex_unlock(&fp->f_lock); 85 pthread_mutex_unlock(&hashlock); 86 return; 87 } 88 89 /* remove from list */ 90 idx = HASH(fp); 91 tfp = fh[idx]; 92 if (tfp == fp) { 93 fh[idx] = fp->f_next; 94 } else { 95 while (tfp->f_next != fp) { 96 tfp = tfp->f_next; 97 } 98 tfp->f_next = fp->f_next; 99 } 100 pthread_mutex_unlock(&hashlock); 101 pthread_mutex_unlock(&fp->f_lock); 102 pthread_mutex_destroy(&fp->f_lock); 103 free(fp); 104 105 } else { 106 fp->f_count--; 107 pthread_mutex_unlock(&fp->f_lock); 108 } 109 }
1 #include <unistd.h> 2 #include <stdio.h> 3 #include <stdlib.h> 4 #include <assert.h> 5 #include <pthread.h> 6 7 #define NHASH 29 8 #define HASH(fp) (((unsigned long)(fp)) % NHASH) 9 10 struct foo { 11 struct foo* f_next; /* protected by hashlock */ 12 int f_count; /* protected by hashlock */ 13 pthread_mutex_t f_lock; 14 int f_id; 15 /* more stuff here */ 16 }; 17 18 struct foo* fh[NHASH]; 19 pthread_mutex_t hashlock = PTHREAD_MUTEX_INITIALIZER; 20 21 struct foo* foo_alloc(void) 22 { 23 int idx = 0; 24 struct foo* fp = malloc(sizeof(struct foo)); 25 if (fp != NULL) { 26 fp->f_count = 1; 27 int ret = pthread_mutex_init(&fp->f_lock, NULL); 28 if (ret != 0) { 29 free(fp); 30 return NULL; 31 } 32 idx = HASH(fp); 33 pthread_mutex_lock(&hashlock); 34 fp->f_next = fh[idx]; 35 fh[idx] = fp->f_next; 36 pthread_mutex_lock(&fp->f_count); 37 pthread_mutex_unlock(&hashlock); 38 /* continue initialization */ 39 } 40 return fp; 41 } 42 43 void foo_increase(struct foo* fp) 44 { 45 assert(fp != NULL); 46 pthread_mutex_lock(&hashlock); 47 fp->f_count++; 48 pthread_mutex_unlock(&hashlock); 49 } 50 51 struct foo* foo_find(int id) 52 { 53 struct foo* fp = NULL; 54 int idx = HASH(fp); 55 pthread_mutex_lock(&hashlock); 56 for (fp = fh[idx]; fp != NULL; fp = fp->f_next) { 57 if (fp->f_id == id) { 58 fp->f_count++; 59 break; 60 } 61 } 62 pthread_mutex_unlock(&hashlock); 63 return fp; 64 } 65 66 void foo_decrease(struct foo* fp) 67 { 68 assert(fp != NULL); 69 struct foo* tfp = NULL; 70 int idx = 0; 71 72 pthread_mutex_lock(&hashlock); 73 if (--fp->f_count == 0) { 74 idx = HASH(fp); 75 tfp = fh[idx]; 76 if (tfp == fp) { 77 fh[idx] = fp->f_next; 78 } else { 79 while (tfp->f_next != fp) { 80 tfp = tfp->f_next; 81 } 82 tfp->f_next = fp->f_next; 83 } 84 pthread_mutex_unlock(&hashlock); 85 pthread_mutex_destroy(&fp->f_lock); 86 free(fp); 87 } else { 88 pthread_mutex_unlock(&hashlock); 89 } 90 }
#include<pthread.h> int pthread_attr_init(pthread_attr_t* attr); int pthread_attr_destroy(pthread_attr_t* attr);
#include <pthread.h> int pthread_mutexattr_init(pthread_mutexattr_t* attr); int pthread_mutexattr_destroy(pthread_mutexattr_t* attr);