在Linux中,多線程的本質仍是進程,它與進程的區別:
進程:獨立地址空間,擁有PCB
線程:也有PCB,但沒有獨立的地址空間(共享)
線程的特點:
1,線程是輕量級進程,有PCB,創建線程使用的底層函數和進程一樣,都是clone
2,從內核看進程和線程是一樣的,都有各自不同的PCB
3,進程可以蛻變成線程
4,在LINUX中,線程是最小的執行單位,進程是最小的分配資源單位
查看指定線程的LWP號命令:
ps -Lf pid
線程優點:
提高程序並發性
開銷小
數據通信,共享數據方便
線程缺點:
庫函數 ,不穩定
調試,編寫困難,GDB
對信號支持不好
線程屬性,可以在一開始就設置好分離態,具體在下面的代碼有說明!
線程同步,主要有互斥鎖mutex,讀寫鎖,條件變量,信號量
線程創建函數原型:
int pthread_create( pthread_t *thread, // 線程ID const pthread_attr_t *attr, // 線程屬性 void *(*start_routine) (void *), // 線程主函數 void *arg // 主函數參數 );
粘上基本創建線程模型:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <unistd.h> #include <pthread.h> //函數回調 void *mythread(void *args) { printf("child thread id==[%ld]\n", pthread_self()); } int main() { pthread_t thread; //創建一個線程 int ret = pthread_create(&thread, NULL, mythread, NULL); if(ret!=0) { printf("pthread_create error, [%s]\n", strerror(ret)); return -1; } printf("main thread id==[%ld]\n", pthread_self()); sleep(1); }
線程屬性,在創建時分離代碼:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <unistd.h> #include <pthread.h> void *mythread(void *args) { printf("child thread id==[%ld]\n", pthread_self()); } int main() { pthread_t thread; //線程屬性 pthread_attr_t attr; //線程屬性初始化 pthread_attr_init(&attr); //設置線程到分離屬性 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); //創建一個線程 int ret = pthread_create(&thread, &attr, mythread, NULL); if(ret!=0) { printf("pthread_create error, [%s]\n", strerror(ret)); return -1; } printf("main thread id==[%ld]\n", pthread_self()); sleep(1); ret = pthread_join(thread, NULL); if(ret!=0) { printf("pthread_join error, [%s]\n", strerror(ret)); } //釋放線程屬性 pthread_attr_destroy(&attr); return 0; }
互斥鎖實現代碼:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <unistd.h> #include <pthread.h> #include <time.h> //定義一把鎖 pthread_mutex_t mutex; void *mythread1(void *args) { while(1) { //加鎖 pthread_mutex_lock(&mutex); pthread_mutex_lock(&mutex); printf("hello "); sleep(rand()%3); printf("world\n"); //解鎖 pthread_mutex_unlock(&mutex); sleep(rand()%3); } pthread_exit(NULL); } void *mythread2(void *args) { while(1) { //加鎖 pthread_mutex_lock(&mutex); printf("HELLO "); sleep(rand()%3); printf("WORLD\n"); //解鎖 pthread_mutex_unlock(&mutex); sleep(rand()%3); } pthread_exit(NULL); } int main() { int ret; pthread_t thread1; pthread_t thread2; //隨機數種子 srand(time(NULL)); //互斥鎖初始化 pthread_mutex_init(&mutex, NULL); ret = pthread_create(&thread1, NULL, mythread1, NULL); if(ret!=0) { printf("pthread_create error, [%s]\n", strerror(ret)); return -1; } ret = pthread_create(&thread2, NULL, mythread2, NULL); if(ret!=0) { printf("pthread_create error, [%s]\n", strerror(ret)); return -1; } //等待線程結束 pthread_join(thread1, NULL); pthread_join(thread2, NULL); //釋放互斥鎖 pthread_mutex_destroy(&mutex); return 0; }
讀寫鎖代碼:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <unistd.h> #include <pthread.h> int number = 0; //定義一把讀寫鎖 pthread_rwlock_t rwlock; void *fun_write(void *args) { int i = *(int *)args; int n; while(1) { //加寫鎖 pthread_rwlock_wrlock(&rwlock); n = number; n++; //sleep(rand()%3); number = n; printf("W->[%d]:[%d]\n", i, number); //解寫鎖 pthread_rwlock_unlock(&rwlock); sleep(rand()%3); } pthread_exit(NULL); } void *fun_read(void *args) { int i = *(int *)args; while(1) { //加讀鎖 pthread_rwlock_rdlock(&rwlock); printf("R->[%d]:[%d]\n", i, number); //解鎖 pthread_rwlock_unlock(&rwlock); sleep(rand()%3); } pthread_exit(NULL); } int main() { int i; int ret; int n = 8; int arr[8]; pthread_t thread[8]; //讀寫鎖初始化 pthread_rwlock_init(&rwlock, NULL); //創建3個寫線程 for(i=0; i<3; i++) { arr[i] = i; ret = pthread_create(&thread[i], NULL, fun_write, (void *)&arr[i]); if(ret!=0) { printf("pthread_create error, [%s]\n", strerror(ret)); return -1; } } //創建5個讀線程 for(i=3; i<n; i++) { arr[i] = i; ret = pthread_create(&thread[i], NULL, fun_read, (void *)&arr[i]); if(ret!=0) { printf("pthread_create error, [%s]\n", strerror(ret)); return -1; } } for(i=0; i<n; i++) { //回收子線程 pthread_join(thread[i], NULL); } //釋放讀寫鎖資源 pthread_rwlock_destroy(&rwlock); return 0; }
cond條件變量代碼:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <unistd.h> #include <pthread.h> typedef struct node { int data; struct node *next; }NODE; //鏈表頭節點指針 NODE *head = NULL; //互斥鎖 pthread_mutex_t mutex; //條件變量 pthread_cond_t cond; //生產者線程處理函數 void *producer(void *args) { NODE *pNode = NULL; while(1) { pNode = (NODE *)malloc(sizeof(NODE)); if(pNode==NULL) { perror("malloc error\n"); exit(1); } pNode->data = rand()%1000; //lock共享資源 pthread_mutex_lock(&mutex); pNode->next = head; head=pNode; printf("P:[%d]\n", head->data); //對共享資源解鎖 pthread_mutex_unlock(&mutex); //使用條件變量解除對線程到阻塞 pthread_cond_signal(&cond); sleep(rand()%3); } } //消費者線程處理函數 void *consumer(void *args) { NODE *pNode = NULL; while(1) { //lock共享資源 pthread_mutex_lock(&mutex); if(head==NULL) { //條件不滿足阻塞等待head不為空 pthread_cond_wait(&cond, &mutex); } printf("C:[%d]\n", head->data); pNode = head; head = head->next; //對共享資源解鎖 pthread_mutex_unlock(&mutex); free(pNode); pNode = NULL; sleep(rand()%3); } } int main(int argc, char *argv[]) { int ret; pthread_t thread1; pthread_t thread2; pthread_mutex_t mutex; pthread_cond_t cond; //初始化互斥鎖 pthread_mutex_init(&mutex, NULL); //初始化條件變量 pthread_cond_init(&cond, NULL); //創建生產者線程 ret = pthread_create(&thread1, NULL, producer, NULL); if(ret!=0) { printf("pthread_create error, [%s]\n", strerror(ret)); return -1; } //創建消費者線程 ret = pthread_create(&thread2, NULL, consumer, NULL); if(ret!=0) { printf("pthread_create error, [%s]\n", strerror(ret)); return -1; } //主線程回收子線程 pthread_join(thread1, NULL); pthread_join(thread2, NULL); //釋放鎖資源 pthread_mutex_destroy(&mutex); //釋放條件變量資源 pthread_cond_destroy(&cond); return 0; }
信號量,經典消費者生產者模型:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <unistd.h> #include <pthread.h> #include <semaphore.h> typedef struct node { int data; struct node *next; }NODE; //鏈表頭節點指針 NODE *head = NULL; sem_t sem_consumer; sem_t sem_producer; //生產者線程處理函數 void *producer(void *args) { NODE *pNode = NULL; while(1) { pNode = (NODE *)malloc(sizeof(NODE)); if(pNode==NULL) { perror("malloc error\n"); exit(1); } pNode->data = rand()%1000; //sem_producer--, 若為0則阻塞 sem_wait(&sem_producer); pNode->next = head; head=pNode; printf("P:[%d]\n", head->data); //sem_consumer++ sem_post(&sem_consumer); sleep(rand()%3); } } //消費者線程處理函數 void *consumer(void *args) { NODE *pNode = NULL; while(1) { //sem_consumer--, 若為0則阻塞 sem_wait(&sem_consumer); printf("C:[%d]\n", head->data); pNode = head; head = head->next; //sem_producer++ sem_post(&sem_producer); free(pNode); pNode = NULL; sleep(rand()%3); } } int main(int argc, char *argv[]) { int ret; pthread_t thread1; pthread_t thread2; //信號量初始化 sem_init(&sem_producer, 0, 5); sem_init(&sem_consumer, 0, 0); //創建生產者線程 ret = pthread_create(&thread1, NULL, producer, NULL); if(ret!=0) { printf("pthread_create error, [%s]\n", strerror(ret)); return -1; } //創建消費者線程 ret = pthread_create(&thread2, NULL, consumer, NULL); if(ret!=0) { printf("pthread_create error, [%s]\n", strerror(ret)); return -1; } //主線程回收子線程 pthread_join(thread1, NULL); pthread_join(thread2, NULL); //釋放信號量資源 sem_destroy(&sem_producer); sem_destroy(&sem_consumer); return 0; }