包括 可执行的程序文本、程序全局内存、堆内存以及文件描述符数组
#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);