Linux 系統編程一一線程

什麼是線程
線程是 CPU 調度和分派的基本單位。線程存在於進程中,共享進程的資源。爲了減少系統開銷,從進程中演化出了線程。線程自己不擁有資源,但它可以去訪問其所屬進程的資源。

進程和線程的關係
通常在一個進程中可以包含若干個線程,它們可以利用進程的所擁有的資源。但是線程是屬於進程的,而進程是擁有資源且進程間相互獨立。不僅進程間可以併發執行,而且在一個進程中的多個線程之間也可以併發執行。

線程常見函數原型

線程的創建
int pthread_create(pthread_t *restrict thread,const pthread_attr_t *restrict attr,
void *(start_routine)(void), void *restrict arg);

功能:
在一個進程中創建一個新的線程,其屬性由attr指定。如果attr爲空,則默認屬性爲應使用。
參數:
thread:線程標識符地址。
attr:線程屬性結構體地址。
start_routine:線程函數的入
arg:傳給線程函數的參數。
返回值:
如果成功,pthread_create()函數將返回0;
否則,將返回一個錯誤號來指示錯誤。

線程等待
int pthread_join(pthread_t thread, void **value_ptr);
功能:
除非目標線程已經終止,否則pthread_join()函數將暫停調用線程的執行,直到目標線程終止爲止。pthread_join函數會使調用者阻塞。

參數:
thread:被等待的線程號。
value_ptr:用來存儲線程退出狀態的指針的地址。

返回值
如果成功,pthread_join()函數將返回0;
否則,將返回一個錯誤號來指示錯誤。

驗證pthread_join是否有線程等待(阻塞)效果。線程函數的程序在 pthread 庫中,鏈接時要加上參數-lpthread。

#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <string.h>
#include <stdlib.h>

void *Pthread_test(void *argv)
{
	static int i_num = 55;
	sleep(2);//兩秒後,將返回
	return (&i_num);
}


int main(int argc, char const *argv[])
{
	
	int ret = 0;
	pthread_t tid1;
	void *i_value = NULL;

	if ((ret = pthread_create(&tid1,NULL,Pthread_test,NULL)) != 0)
	{
		perror("pthread_create");
		exit(1);
	}

	pthread_join(tid1,&i_value); //等待線程,接收線程返回值
	printf("i_value = %d\n",*((int *)i_value));

	return 0;
}

輸出結果
在這裏插入圖片描述線程函數傳參

#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <string.h>
#include <stdlib.h>

void *Pthread_test(void *argv)
{
	int i_num = 0;
	sleep(1);
	i_num = *((int*)argv);
	printf("i_num = %d\n", i_num);
	return NULL;
}


int main(int argc, char const *argv[])
{
	
	int ret = 0;
	pthread_t tid1;
	int i_value = 66;
	if ((ret = pthread_create(&tid1,NULL,Pthread_test,(void *)&i_value)) != 0)
	{
		perror("pthread_create");
		exit(1);
	}

	pthread_join(tid1,NULL);//線程等待,接收線程返回值爲NULL

	return 0;
}

輸出結果
在這裏插入圖片描述

線程分離
int pthread_detach(pthread_t thread);
功能:
當線程終止時,可以回收線程的存儲。如果線程沒有終止,pthread_detach()不會導致線程終止。pthread_detach()使調用線程與當前進程分離。成爲一個獨立的線程,該線程終止時,系統將自動回收它的資源。
參數:
thread:線程號
返回值:
如果調用成功,pthread_detach()將返回0;
否則,將返回一個錯誤號來指示錯誤。

線程退出
void pthread_exit(void *value_ptr);
功能:
函數pthread_exit()將終止調用線程,並使value_ptr值對任何成功連接到終止線程的線程可用。
參數:
value_ptr:存儲線程退出狀態的指針。

註冊清理函數與彈出清理函數
void pthread_cleanup_pop(int execute);
功能:
函數pthread_cleanup_pop()將刪除調用線程的取消清理堆棧頂部的例程,並可選地調用它。
參數:
execute:線程清理函數執行標誌位。
非 0,彈出清理函數,執行清理函數。
0,彈出清理函數,不執行清理函數。
void pthread_cleanup_push(void (routine)(void), void *arg);
功能:
將指定的取消清理處理程序例程推入調用線程的取消清理堆棧。
參數:
routine:線程清理函數的指針。
arg:傳給線程清理函數的參數。

取消線程

int pthread_cancel(pthread_t thread);
功能:
請求線程被取消。目標線程的可取消狀態和類型決定了取消何時生效。pthread_cancel是指取消一個正在執行線程的操作。
參數:
thread:目標線程 ID。
返回值:
如果成功,pthread_cancel()函數將返回0;
否則,將返回一個錯誤號來指示錯誤。

當線程執行以下動作時會調用清理函數:
1、調用 pthread_exit 退出線程。
2、響應其它線程的取消請求。
3、用非零 execute 調用 pthread_cleanup_pop。
無論哪種情況 pthread_cleanup_pop 都將刪除上一次 pthread_cleanup_push 調用註冊的清理處理函數。

調用 pthread_cleanup_pop 函數時,系統自動調用線程清理函數

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <string.h>

void cleanup_func1(void *arg)
{
	printf("cleanup_func1\n");
	printf("clean up ptr = %s\n", (char *)arg); //清理拷貝字符串
	free((char *)arg);
}

void cleanup_func2(void *arg)
{
	printf("cleanup_func2\n");
}

void *Pthread_test(void *arg)
{
	char *ptr = NULL;
	ptr = (char*)malloc(100);
	pthread_cleanup_push(cleanup_func1, (void*)(ptr));  
	pthread_cleanup_push(cleanup_func2, NULL); 
	bzero(ptr, 100); //清空緩衝區
	strcpy(ptr, "Cats love dogs");
	pthread_cleanup_pop(1);
	pthread_cleanup_pop(1);
	return NULL;
}

int main(int argc, char *argv[])
{
	pthread_t tid;
	int ret = 0;

	if ((ret = pthread_create(&tid, NULL, Pthread_test, NULL)) != 0) // 創建一個線程
	{
		perror("pthread_create");		
	}
	pthread_join(tid,NULL);//線程等待,接收線程返回值爲NULL
	return 0;
}


編譯結果
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章