在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;
}
