Linux多線程實現及線程同步函數分析


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

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM