歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux基礎 >> Linux基礎知識 >> linux系統編程:線程原語

linux系統編程:線程原語

日期:2017/3/2 17:15:16   编辑:Linux基礎知識

線程原語

線程概念

線程(thread),有時被稱為輕量級進程(Lightweight Process,LWP)。是程序運行流的最小單元。一個標准的線程由線程ID。當前指令指針(PC),寄存器集合和堆棧組成。

很多其他詳解看百度百科:線程。

在Linux shell下通過命令 $ ps -Lf pid 查看指定pid號下的全部線程。


線程之間的共享與非共享

這裡的線程是指同一進程下的線程。

共享:

1.文件描寫敘述符表
2.每種信號的處理方式
3.當前工作文件夾
4.用戶ID和組ID
5.內存地址空間

非共享:

1.線程id
2.處理器現場和棧指針(內核棧)
3.獨立的棧空間(用戶空間棧)
4.errno變量
5.信號屏蔽字
6.調度優先級


線程原語

通過命令 $ man -k pthread 查看系統下與線程有關的全部函數。

一般的,把main函數稱作主線程或主控線程,其他線程都稱作是子線程。

創建線程

#include <pthread.h>
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg);

pthread_t *thread:傳遞一個pthread_t變量地址進來,用於保存新線程的tid(線程ID)

const pthread_attr_t *attr:線程屬性設置。如使用默認屬性,則傳NULL

void *(*start_routine)(void *):函數指針。指向新線程應該載入運行的函數模塊

void *arg:指定線程將要載入調用的那個函數的參數

返回值:成功返回0,失敗返回錯誤號。

曾經學過的系統函數都是成功返回0,失敗返回-1。而錯誤號保存在全局變量errno中,而pthread庫的函數都是通過返回值返回錯誤號,盡管每一個線程也都有一個errno,但這是為了兼容其他函數接口而提供的,pthread庫本身並不使用它。通過返回值返回錯誤碼更加清晰。
Compile and link with -lpthread.
typedef unsigned long int pthread_t; //在不同的系統中pthread_t可能會有不同的實現


結束線程

假設須要僅僅終止某個線程而不終止整個進程。能夠有三種方法:

1.return。

這樣的方法對主控線程不適用。從main函數return相當於調用exit。

2.一個線程能夠調用pthread_cancel終止同一進程中的還有一個線程。

#include <pthread.h>
int pthread_cancel(pthread_t thread);
被取消的線程,退出值。定義在Linux的pthread庫中常數PTHREAD_CANCELED的值是-1。能夠在頭文件pthread.h中找到它的定義:#define PTHREAD_CANCELED ((void *) -1)。也就是說,被pthread_cancel結束的線程,退出值,都是-1。

同一進程的線程間,pthread_cancel向還有一線程發終止信號。

系統並不會立即關閉被取消線程,僅僅有在被取消線程下次系統調用時,才會真正結束線程。

或調用pthread_testcancel,讓內核去檢測是否須要取消當前線程。

3.線程能夠調用pthread_exit終止自己。

#include <pthread.h>
void pthread_exit(void *retval);
void *retval:線程退出時傳遞出的參數。能夠是退出值或地址,如是地址時,不能是線程內部申請的局部地址。

在不論什麼地方調用exit,都會使整個進程退出。


線程id

#include <pthread.h>
pthread_t pthread_self(void);
RETURN VALUE
This function always succeeds, returning the calling thread’s ID.
在線程中使用pthread_self。獲取線程id。



回收線程

#include <pthread.h>
int pthread_join(pthread_t thread, void **retval);
pthread_t thread:回收線程的tid
void **retval:接收退出線程傳遞出的返回值
返回值:成功返回0。失敗返回錯誤號
同進程相似,線程退出後,相同須要進行回收,所以pthread_join相似於wait。調用該函數的線程將掛起等待,直到id為thread的線程終止。thread線程以不同的方法終止,通過pthread_join得到的終止狀態是不同的。總結例如以下:
  1. 假設thread線程通過return返回,retval所指向的單元裡存放的是thread線程函數的返回值。

  2. 假設thread線程被別的線程調用pthread_cancel異常終止掉,retval所指向的單元裡存放的是常數PTHREAD_CANCELED。
  3. 假設thread線程是自己調用pthread_exit終止的。retval所指向的單元存放的是傳給pthread_exit的參數。
假設對thread線程的終止狀態不感興趣,能夠傳NULL給retval參數。


代碼演示樣例

使用return和pthread_exit結束進程

//thread_exit.c
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
void *fun_1(void *argv)
{
	printf("Hello %s,my thread id is %x\n", (char*)argv, pthread_self());
	sleep(1);
	//pthread_exit((void*)1);
	return (void*)1;
}
void *fun_2(void *argv)
{
	printf("Hello %c, my thread id is %x\n", (char)argv, pthread_self());
	sleep(2);
	pthread_exit((void*)"David");
}
int main(void)
{
	int *ret1;
	char *ret2;
	pthread_t tid1, tid2;
	pthread_create(&tid1, NULL, fun_1, (void*)"zhangxiang");
	pthread_create(&tid2, NULL, fun_2, (void*)'D');
	pthread_join(tid1, (void*)&ret1);
	pthread_join(tid2, (void*)&ret2);
	printf("thread %x exit with %x\n", tid1, ret1);
	printf("thread %x exit with %s\n", tid2, ret2);
	return 0;
}
$ gcc thread_exit.c -lpthread
$ ./a.out
Hello D, my thread id is 745e9700
Hello zhangxiang, my thread id is 74fea700
thread 74fea700 exit with 1
thread 745e9700 exit with David

使用pthread_cancel終止還有一個線程

//thread_cancel.c
#include <stdio.h>
#include <pthread.h>
void *fun(void *argv)
{
	printf("thread %x running\n", pthread_self());
	pthread_exit((void*)0);
}
int main(void)
{
	pthread_t tid;
	void *ret;
	pthread_create(&tid, NULL, fun, NULL);
	pthread_join(tid, &ret);
	printf("thread %x exit with %d\n", tid, (int)ret);
	pthread_create(&tid, NULL, fun, NULL);
	pthread_cancel(tid);
	pthread_join(tid, &ret);
	printf("thread %x exit with %d\n", tid, (int)ret);
	return 0;
}
$ gcc thread_cancel.c -lpthread
$ a.out
thread 96da9700 running
thread 96da9700 exit with 0
thread 96da9700 running
thread 96da9700 exit with -1


既能夠在主線程中使用pthread_cancel終止子線程。也能夠在子線程中終止還有一個子線程。




CCPP Blog 文件夾


Copyright © Linux教程網 All Rights Reserved