執行緒初步(1)—— 執行緒的建立、引數和返回值、結束、狀態、取消
1執行緒(thread)的概念和特點
網路一般都需要實現程式碼的並行。程式碼的並行必須藉助多程序/多執行緒。
主流作業系統中都是支援多程序,而在每個程序的內部,都支援多執行緒並行。
程序,重量級的,擁有自己獨立的記憶體空間。
執行緒,輕量級的,不需要擁有自己獨立的記憶體空間,只是額外擁有一個獨立的棧。一個程序記憶體的所有執行緒共享程序的資源(程式碼區、全域性區、堆、檔案目錄……)。
程序中支援多執行緒並行,其中有一個是主執行緒,程序中必須有主執行緒(main函式)。
因此網路開發經常是網路+多執行緒模式。
2 執行緒的實現原理
計算機程式執行的硬體必備:CPU、記憶體。如果要並行,意味著CPU和記憶體都應該可分。記憶體是可分的,但CPU不可分,那麼多執行緒怎麼並行?
主流作業系統採用CPU時間片技術實現多執行緒的並行。
多執行緒之間互相獨立,但又互相影響。
主執行緒一旦結束,程序隨之結束,程序結束導致所有執行緒結束。
多執行緒之間程式碼是亂序執行,每個執行緒內部的程式碼是順序執行。
3 執行緒的實現
POSIX規範中對執行緒做了比較完善的定義,因此,執行緒編碼使用 pthread.h,幾乎所有的函式都以pthread_ 開頭。程式碼在libpthread.so中。
比如:建立執行緒的函式:
pthread_create()
4個指標型別做引數:
第一個引數:用於儲存pthread_t 型別的執行緒ID
第二個引數: 執行緒屬性,一般為0即可(預設屬性)
第三個引數和第四個引數聯合使用,第三個引數是函式指標,把執行緒需要執行的程式碼寫在函式中,函式的引數由第四個引數提供。
void* (*fun) (void*)
返回,成功返回0,失敗返回錯誤碼。執行緒的函式錯誤處理通過返回錯誤碼的方式,而不是使用errno。
#include <stdio.h>
#include <pthread.h>
#include <string.h>
void* task(void* p){
int i;
for(i=0;i<100;i++){
printf("task:%d\n",i);
}
}
int main(){
pthread_t id;//用來儲存執行緒ID
printf("size=%d\n",sizeof(id));
int res = pthread_create(&id,0,task,0);
if(res/*!=0*/)
printf("create error:%s\n",strerror(res));//執行緒錯誤處理
int i;
for(i=0;i<100;i++){
printf("main:%d\n",i);
}
sleep(1);
}
4 執行緒的引數和返回值
4.1 執行緒的引數
在使用執行緒的引數時,必須保證引數的指向有效。
pthread_join()可以讓一個執行緒等待另外一個執行緒結束,並且取得結束執行緒的返回值。(類似wait)
#include <stdio.h>
#include <pthread.h>
void* task(void* p){//p就是create()第4個引數
int* pi = p;
printf("*pi=%d\n",*pi);
*pi = 200;
}
//練習:執行緒傳入圓的半徑,列印圓的面積
void* task2(void* p){
double* pd = p;
printf("s=%lf\n",3.14*(*pd)*(*pd));
}
int main(){
pthread_t id1,id2,id3;
int x = 100;
pthread_create(&id1,0,task,&x);
id2 = pthread_self();//取當前執行緒的ID
printf("id1=%u,main=%u\n",id1,id2);
pthread_join(id1,0);
printf("x=%d\n",x);
double d = 1.0;
pthread_create(&id3,0,task2,&d);
pthread_join(id3,0);
}
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
void* task(void* p){
int x = (int)p;//可以拿指標當int用
printf("x=%d\n",x);
}
void* task2(void* p){
sleep(1);
int* pi = p;//p已經被釋放,無效
printf("*pi=%d\n",*pi);
}
int main(){
pthread_t id1,id2;
int x = 100;
pthread_create(&id1,0,task,(void*)x);//傳int
pthread_join(id1,0);
int* pi = malloc(4); *pi = 100;
pthread_create(&id2,0,task2,pi);
free(pi); pthread_join(id2,0);
}
4.2 執行緒的返回值
關於函式/執行緒的返回值:
1 不能直接以陣列做返回型別;
2 能返回區域性變數,但不能返回指向區域性變數的指標;
3 加了static的變數指標可以返回。
執行緒的返回值必須是一個有效的指標:全域性變數、常量、傳入的指標、static的區域性變數。
執行緒的返回值可以pthread_join的第二個引數取得:
pthread_join(pthread_t id,void** retval)
取返回值時,相當於程式碼:
*(retval) = 執行緒的返回值
#include <stdio.h>
#include <pthread.h>
#include <string.h>
void* task(void* p){
printf("%s\n",(char*)p);
//p = "hello";//改地址,p指向只讀常量區
strcpy(p,"hello");//沒有改地址main()有效
//char st[] = "hello";//區域性變數,返回無效
//return st;
return p;//res = p;
}
//練習:線上程中計算1-10的和,並返回給main
void* task2(void* p){
/*static*/ int sum = 0;
int i;
for(i=1;i<11;i++){
sum = sum+i;
}
return (void*)sum;//∑
}
int main(){
char str[] = "abcde"; pthread_t id;
pthread_create(&id,0,task,str);
char* res;//res是 野指標
pthread_join(id,(void**)&res);//res = p;
printf("res=%s\n",res);
pthread_create(&id,0,task2,0);
//int* pi;
//pthread_join(id,(void**)&pi);
//printf("*pi=%d\n",*pi);
int x;
pthread_join(id,(void**)&x);
printf("x=%d\n",x);
}
5 執行緒的結束
正常結束:
執行緒函式結束
pthread_exit(void* retval),與return一樣
非正常結束:
出錯/被其他執行緒取消
注:exit()結束的是程序,所以不能用於結束執行緒。
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
void* task(void* p){
int i;
for(i=0;i<100;i++){
//if(i == 12) return (void*)i;
//if(i == 12) pthread_exit((void*)i);
if(i == 12) exit(i);//結束程序
}
}
int main(){
pthread_t id;
pthread_create(&id,0,task,0);
int res;
pthread_join(id,(void**)&res);
printf("res=%d\n",res);
}
6 執行緒的狀態
執行緒在啟動後,可以通過不同的函式進入不同的狀態:
pthread_join() 進入非分離狀態(同步),非分離狀態的執行緒會在pthread_join()結束後回收執行緒資源。
pthread_detach() 進入分離狀態(非同步),分離狀態的執行緒會線上程結束後直接回收執行緒的資源。
已經處於分離狀態的執行緒 join()沒有效果。執行緒最好處於這兩種狀態其中的一種。
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
void* task(void* p){
int i;
for(i=0;i<10;i++){
printf("task:%d\n",i); usleep(100000);
}
}
int main(){
pthread_t id;
pthread_create(&id,0,task,0);
pthread_detach(id);
pthread_join(id,0);
int i;
for(i=0;i<10;i++){
printf("main:%d\n",i); usleep(100000);
}
}
7 執行緒的取消(瞭解)
執行緒的取消就是給目標執行緒發CANCEL訊號,目標執行緒可以做出3種選擇:忽略、立刻停止、過一會再停止。
執行緒取消的相關函式:
pthread_cancel() 給目標執行緒發取消訊號
pthread_setcancelstate() 設定是否支援取消
pthread_setcanceltype() 設定取消的方式
#include <stdio.h>
#include <pthread.h>
void* task1(void* p){
//pthread_setcancelstate(//不能取消
//PTHREAD_CANCEL_DISABLE,0);
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,0);
//pthread_setcanceltype(//立即取消
//PTHREAD_CANCEL_ASYNCHRONOUS,0);
pthread_setcanceltype(//到下一個取消點
PTHREAD_CANCEL_DEFERRED,0);
while(1)
printf("-----------\n"),usleep(1);
}
void* task2(void* p){
sleep(3);
printf("取消執行緒1\n");
pthread_cancel(*(pthread_t*)p);
}
int main(){
pthread_t id1,id2;
pthread_create(&id1,0,task1,0);
pthread_create(&id2,0,task2,&id1);
pthread_join(id1,0); pthread_join(id2,0);
}
相關推薦
執行緒初步(1)—— 執行緒的建立、引數和返回值、結束、狀態、取消
1執行緒(thread)的概念和特點 網路一般都需要實現程式碼的並行。程式碼的並行必須藉助多程序/多執行緒。 主流作業系統中都是支援多程序,而在每個程序的內部,都支援多執行緒並行。 程序,重量級的,擁有自己獨立的記憶體空間。 執行緒,輕量
Java多執行緒程式設計-(1)-執行緒安全和鎖Synchronized概念
一、程序與執行緒的概念 (1)在傳統的作業系統中,程式並不能獨立執行,作為資源分配和獨立執行的基本單位都是程序。 在未配置 OS 的系統中,程式的執行方式
第11章——《執行緒》(1)
實驗環境介紹 gcc:4.8.5 glibc:glibc-2.17-222.el7.x86_64 os:Centos7.4 kernel:3.10.0-693.21.1.el7.x86_64 執行緒概念 忽略(ps:Linux是用程序實
多執行緒學習(1)
優點:多程序,多執行緒可以讓程式不被阻塞.可以充分利用多核cpu的優勢,提高執行效率 建立方式: (1)通過繼承Thread類,並重寫其中的run方法來出建立 Thread t = new Thread() { public void run() { // 執行 //
java多執行緒知識(1)
基礎概念 1.執行緒和程序: 程序有自己的獨立空間,而執行緒共享程序的空間 執行緒通訊方便,同一程序的執行緒共享全域性變數,靜態資料 多程序更健壯,多執行緒只要有一個執行緒死掉,整個程序也死 2.同步和非同步:同步必須等該方法的呼叫返回 3.並行和
JVM除錯常用命令——jstack命令與Java執行緒棧(1)
1 jstack 命令 jstack命令的主要作用是列印指定Java程序中每一個執行緒的工作狀態,以及每個執行緒棧當前的方法執行順序等詳細情況。為什麼jstack命令不和jmap、jinfo、jstat等命令一同講解,而要單獨成文呢?因為通過jstack命令給出的執行緒棧詳細情況,可
執行緒基礎(1)
概念 執行程式會建立一個程序。是OS排程的最小單元是執行緒(輕量級程序)。 普通的java程式包含的執行緒: 11:Monitor Ctrl-Break //監聽中斷訊號 5:Attach Listener //獲取記憶體dump,執行緒dump 4:Signal Dispatcher /
java執行緒複習(1)
Java 程序與執行緒的對比 程序是資源分配的最小單位,執行緒是程式執行的最小單位,是系統獨立排程和分派 CPU 的基本單位 程序有自己的獨立地址空間,每啟動一個程序,系統就會為它分配地址空間,建立資料表來維護程式碼段、堆疊段和資料段,這種操作非常昂貴。而執行緒是共享程序中
C++ 多執行緒框架(1):new 一下就啟動一個執行緒
幾年前寫過一個C++的多執行緒框架,雖然寫完了,但是人一懶做了一次說明以後就沒影了,最近把程式碼整理了一下,準備發到github上,在這裡,再把這個框架總結一下吧。 多執行緒一直是程式設計中常見的問題,特別是在Linux的c++上,多執行緒的封裝一直不是很好,當然,
java 執行緒池(1)
ThreadPoolExecutor概述 ThreadPoolExecutor 下文簡稱 TPE ,我們使用它都是從Executror 這個類中的方法 : 1 public static Executo
執行緒學習(1)
建立執行緒 執行緒是一條獨立的執行流,有自己的程式執行計數器,有自己的棧。 Java中建立執行緒有兩種方式: 一種是繼承Thread,另外一種是實現Runnable介面. 繼承Thread類: public class HelloThread extends Thread {
多執行緒(1)-執行緒的終止方法
前言 近期看了一本關於多執行緒的書籍《Java多執行緒程式設計核心技術》。下面對學習到的關於執行緒的終止方法進行總結,如果有錯誤歡迎大家指出,如果對大家有幫助,歡迎轉載和點贊。 概述 java中
執行緒初步(二)
今天我們將通過執行緒來談一談生產者消費者的問題 首先我們寫一個小程式生產一個商品並消費一個商品 /** * 寫一個商品者生產消費者消費的執行緒小程式 * @author lover * */ class goods{ private i
java併發程式設計(一) 執行緒安全(1)
最近想了解併發程式設計,二執行緒安全是它的基礎。所以看了下java相關的執行緒安全知識。 執行緒安全的核心是程式碼正確性(一般是輸出的結果); 首先無狀態的物件是執行緒安全的;因為一個無狀態的物件即不包含其他域;也沒有對其他域的引用; (1)原子性 原子性:即程式碼不
Java多執行緒學習(1)——停止執行緒
目錄: 1.interrupt方法學習(基礎知識) 2.異常法 3.sleep法 4.return法 5.stop法(不推薦) 1.interrupt方法學習(基礎知識) 呼叫interrupt方法只是對執行緒做了一個標記(停止標記),並沒有停止執行緒的效果,需要結合以下
併發(1)--執行緒池簡介
通常情況下,當我們使用一個執行緒的時候,採用new方式去建立一個執行緒,這樣實現起來很方便,但是與此同時存在一個問題:大量建立執行緒,會帶來資源的消耗,並且如果併發的數量很多的時候,並且每個執
多執行緒開發(1):主執行緒,前臺執行緒,後臺執行緒,守護執行緒,子執行緒,託管執行緒的關係
1.主執行緒 當一個程式啟動時,就有一個程序被作業系統(OS)建立,與此同時一個執行緒也立刻執行,該執行緒通常叫做程式的主執行緒(Main Thread),因為它是程式開始時就執行的,如果你需要再建立執行緒,那麼建立的執行緒就是這個主執行緒的子執行緒。每個程序至少都有一個
學習使用chromium裡的執行緒類(1)
Chromium就好比是一個寶藏,裡面有很多寶貝。其中我最喜歡的寶貝是base庫和ipc(程序間通訊) 。這兩件寶貝在大型專案開發中會給我們帶來極大的幫助。所以值得我們去花大功夫研究、學習的。在來到我現在所在的公司前,我對chromium的瞭解幾乎沒有,
執行緒初步(五)---join,yield
今天我們來學習一下執行緒裡面的兩個方法 一、join(); join方法:等待執行緒終止。 使用方法 執行緒名.join(); 表示的是當前執行緒加入,當新加入的執行緒加入,原先的執行緒才會開始執行,接下來我們寫一個小程式來演示一
netty原始碼分析之-EventLoop與執行緒模型(1)
執行緒模型確定來程式碼的執行方式,我們總是必須規避併發執行可能會帶來的副作用,所以理解netty所採用的併發模型的影響很重要。netty使用了被稱為事件迴圈的EventLoop來執行任務來處理在連線的生命週期內發生的事件 執行緒模型 對於Even