1. 程式人生 > >linux C++ 面向物件執行緒類封裝

linux C++ 面向物件執行緒類封裝

1.封裝遇到的問題

pthread執行緒封裝為抽象類,這樣使用者在使用執行緒時,只需要繼承一下這個抽象類,並實現相應的介面就可以了。這樣做的好處是使用者可以將注意力集中線上程所要執行的邏輯上,而不需要關注建立執行緒、銷燬執行緒等細節問題上。

我們抽象類的名稱為Thread,其中有一個成員函式run,該函式為的宣告形式為:

void run() = 0;

即將該成員函式宣告為純虛擬函式,使用者繼承此類必須要實現此成員函式。Thread中還有另外一個成員函式start,該函式的宣告形式為:

void start();

使用者在子類中呼叫start方法,將啟動執行緒,並在執行緒中執行run函式。

最常想到的方法就是在start方法中使用pthread_create建立一個執行緒,並呼叫run函式。如下面這樣的實現:

void start() 
{ 
	int status;
 
	status = pthread_create(_pThread,NULL,Thread::run,NULL); 
	if(status != 0) 
 		err_abort(“creating thread failure”,status); 
 
 } 


這樣編譯肯定是不能通過的,這是因為pthread_create要求的執行緒例程的介面形式為:

void *(*thread_routin)(void *args);

而上面程式碼中提供的執行緒例程的介面形式為:

void Thread::run()

顯然不符合要求的介面。

為了能夠在start中呼叫run函式,我們不得不採用一種迂迴的方式。下面提供兩種方法:一種是使用靜態成員函式,另外一種是使用友元函式。

       靜態成員函式的作用域是全域性的,而不僅僅侷限於某個函式中。靜態成員函式的實現方法和C語言中的普通函式類似,因此靜態函式沒有this指標,靜態函式只能操作靜態成員變數。之所以將靜態函式封裝到類中,在很大程度上也只是為了滿足面向物件的特性之一-----封裝性。

2.使用靜態函式

       需要特別注意的是mian函式中使用pthread_create

的執行例程為MyThread類中的執行緒代理函式thread_proxy_func,在此函式中在呼叫run函式,這樣就順利的迂迴到了run函式。基於這種方法,我們可以用靜態函式來封裝一個簡單的抽象類,以下為封裝的程式碼,由三個檔案構成:Thread.h(類的宣告檔案),Thread.cpp(類的實現檔案),main.cpp(測試檔案):

#ifndef THREAD_H
#define THREAD_H
#include <iostream>
#include <pthread.h>

using namespace std;

class Thread
{
private:
    //當前執行緒的執行緒ID
    pthread_t tid;
    //執行緒的狀態
    int threadStatus;
    //獲取執行方法的指標
    static void * thread_proxy_func(void * args);
    //內部執行方法
    void* run1();
public:
    //執行緒的狀態-新建
    static const int THREAD_STATUS_NEW = 0;
    //執行緒的狀態-正在執行
    static const int THREAD_STATUS_RUNNING = 1;
    //執行緒的狀態-執行結束
    static const int THREAD_STATUS_EXIT = -1;
    //建構函式
    Thread();
    //執行緒的執行實體
    virtual void run()=0;
    //開始執行執行緒
    bool start();
    //獲取執行緒ID
    pthread_t getThreadID();
    //獲取執行緒狀態
    int getState();
    //等待執行緒直至退出
    void join();
    //等待執行緒退出或者超時
    void join(unsigned long millisTime);
};

class MultiThread : public Thread
{
public:
    void run()
    {
        int number = 0;
        for (int i = 0; i < 10; i++)
        {
            cout << "Current number is " << number++;
            cout << " PID is " << getpid() << " TID is " << getThreadID() << endl;
            sleep(1);
        }
    }
};

#endif
Thread.cpp
#include "thread.h"


void* Thread::run1()
{
    threadStatus = THREAD_STATUS_RUNNING;
    tid = pthread_self();
    run();
    threadStatus = THREAD_STATUS_EXIT;
    tid = 0;
    pthread_exit(NULL);
}

Thread::Thread()
{
    tid = 0;
    threadStatus = THREAD_STATUS_NEW;
}

bool Thread::start()
{
		int iRet = 0;
    pthread_create(&tid, NULL, thread_proxy_func, this) == 0;
}

pthread_t Thread::getThreadID()
{
    return tid;
}

int Thread::getState()
{
    return threadStatus;
}

void Thread::join()
{
    if (tid > 0)
    {
        pthread_join(tid, NULL);
    }
}
void * Thread::thread_proxy_func(void * args)
{
 		Thread * pThread = static_cast<Thread *>(args); 
 
		pThread->run(); 
 		
 		return NULL; 
}

void Thread::join(unsigned long millisTime)
{
    if (tid == 0)
    {
        return;
    }
    if (millisTime == 0)
    {
        join();
    }else
    {
        unsigned long k = 0;
        while (threadStatus != THREAD_STATUS_EXIT && k <= millisTime)
        {
            usleep(100);
            k++;
        }
    }
}
main.cpp
#include <iostream>
#include <pthread.h>
#include "thread.h"

using namespace std;

int main(int argv,char *argc)
{
	MultiThread tt;
	tt.start();
	tt.join();
	return 0;
}

3.使用友元函式

       友元函式的作用和靜態函式相同,都起到一個代理的作用。需要將物件的指標作為引數傳遞給這個友元函式,然後在友元函式中呼叫run函式。程式碼如下,

由三個檔案構成:Thread.h(類的宣告檔案),Thread.cpp(類的實現檔案),main.cpp(測試檔案):

Thread.h
#ifndef THREAD_H
#define THREAD_H
#include <iostream>
#include <pthread.h>

using namespace std;

class Thread
{
private:
    //當前執行緒的執行緒ID
    pthread_t tid;
    //執行緒的狀態
    int threadStatus;
    //獲取執行方法的指標
    //static void * thread_proxy_func(void * args);
    friend void * thread_proxy_func(void * args);
    //內部執行方法
    void* run1();
public:
    //執行緒的狀態-新建
    static const int THREAD_STATUS_NEW = 0;
    //執行緒的狀態-正在執行
    static const int THREAD_STATUS_RUNNING = 1;
    //執行緒的狀態-執行結束
    static const int THREAD_STATUS_EXIT = -1;
    //建構函式
    Thread();
    //執行緒的執行實體
    virtual void run()=0;
    //開始執行執行緒
    bool start();
    //獲取執行緒ID
    pthread_t getThreadID();
    //獲取執行緒狀態
    int getState();
    //等待執行緒直至退出
    void join();
    //等待執行緒退出或者超時
    void join(unsigned long millisTime);
};

class MultiThread : public Thread
{
public:
    void run()
    {
        int number = 0;
        for (int i = 0; i < 10; i++)
        {
            cout << "Current number is " << number++;
            cout << " PID is " << getpid() << " TID is " << getThreadID() << endl;
            sleep(1);
        }
    }
};

#endif

Thread.cpp
#include "thread.h"


void* Thread::run1()
{
    threadStatus = THREAD_STATUS_RUNNING;
    tid = pthread_self();
    run();
    threadStatus = THREAD_STATUS_EXIT;
    tid = 0;
    pthread_exit(NULL);
}

Thread::Thread()
{
    tid = 0;
    threadStatus = THREAD_STATUS_NEW;
}

bool Thread::start()
{
		int iRet = 0;
    pthread_create(&tid, NULL, thread_proxy_func, this) == 0;
}

pthread_t Thread::getThreadID()
{
    return tid;
}

int Thread::getState()
{
    return threadStatus;
}

void Thread::join()
{
    if (tid > 0)
    {
        pthread_join(tid, NULL);
    }
}
void * thread_proxy_func(void * args)
{
 		Thread * pThread = static_cast<Thread *>(args); 
 
		pThread->run(); 
 		
 		return NULL; 
}

void Thread::join(unsigned long millisTime)
{
    if (tid == 0)
    {
        return;
    }
    if (millisTime == 0)
    {
        join();
    }else
    {
        unsigned long k = 0;
        while (threadStatus != THREAD_STATUS_EXIT && k <= millisTime)
        {
            usleep(100);
            k++;
        }
    }
}

main.cpp
#include <iostream>
#include "thread.h"

using namespace std;

int main(int argv,char *argc)
{
	MultiThread tt;
	tt.start();
	tt.join();
	return 0;
}

執行結果



makefile參考

ANAME=server
CC=g++
TMP_PROGS = main.cpp thread.cpp
PROGS = $(TMP_PROGS)
OBJS = $(PROGS:.cpp=.o)
INCDIR=./

all: $(ANAME)

$(ANAME): $(OBJS)
	@echo "--------------- .o to ELT "
	$(CC) -g $(TMP_PROGS) -o [email protected] -lpthread 
.cpp.o:
	@echo "--------------- CPP to .o "
	$(CC) -g $(CFLAGS) -I$(INCDIR) -c  $< -o [email protected]  -lpthread 

clean:
	$(RM) $(ANAME)
	$(RM) *.o


相關推薦

linux C++ 面向物件執行封裝

1.封裝遇到的問題 將pthread執行緒封裝為抽象類,這樣使用者在使用執行緒時,只需要繼承一下這個抽象類,並實現相應的介面就可以了。這樣做的好處是使用者可以將注意力集中線上程所要執行的邏輯上,而不需要關注建立執行緒、銷燬執行緒等細節問題上。 我們抽象類的名稱為Th

C++11的執行,建立的執行,如何設定優先順序?

SetThreadPriorityThe SetThreadPriority function sets the priority value for the specified thread. This value, together with the priority 

Linux C++的多執行程式設計

1. 引言   執行緒(thread)技術早在60年代就被提出,但真正應用多執行緒到作業系統中去,是在80年代中期,solaris是這方面的佼佼者。傳統的Unix也支援執行緒的概念,但是在一個程序(process)中只允許有一個執行緒,這樣多執行緒就意味著多程序。現在,多執

Linux C++的多執行程式設計(新手最全教程)

1. 引言   執行緒(thread)技術早在60年代就被提出,但真正應用多執行緒到作業系統中去,是在80年代中期,solaris是這方面的佼佼者。傳統的Unix也支援執行緒的概念,但是在一個程序(process)中只允許有一個執行緒,這樣多執行緒就意味著多程序。現在,多執行緒技術已經被許多作業系統所支援

windows程式設計 使用C++實現多執行

本文簡單介紹如何在windows程式設計中實現多執行緒類,供大家學習參考,也希望大家指正。 有時候我們想在一個類中實現多執行緒,主執行緒在某些時刻獲得資料,可以“通知”子執行緒去處理,然後把結果返回。下面的例項是主執行緒每隔2s產生10個隨機數,將這10隨機數傳給多執行緒

Linux C語言多執行庫Pthread中條件變數的的正確用法逐步詳解

(本文的讀者定位是瞭解Pthread常用多執行緒API和Pthread互斥鎖,但是對條件變數完全不知道或者不完全瞭解的人群。如果您對這些都沒什麼概念,可能需要先了解一些基礎知識) Pthread庫的條件變數機制的主要API有三個: int pthread_cond_w

c++封裝物件執行封裝

1. C++面向物件程式設計介紹 面向物件程式設計(Object Oriented Programming),簡稱OOP。 在傳統的面向過程程式設計中,資料以及資料的相關操作函式都是分離的獨立個體; 物件,如周圍的一切其實都是物件;就程式設計角度,物

c++11 thread 封裝成簡單執行

       這幾天學習qt的時候發現Qt的執行緒類和java的執行緒類差不多,因為要讀取攝像頭然後顯示到介面上,執行緒需要不停的讀。大體結構就是這樣了: void run(){ while( !當前執行緒被中斷){ //work } }

C++面向物件執行程式設計》讀後感

開始時間:2010-10-19 結束時間:2010-12-12 閱讀方式:精讀,除附錄部分關於非WIN32系統外的API部分。 圖書介質:掃描PDF 讀後感 用了將近2個月的時間讀完了《C++面向物件多

C++面向物件程式設計——概述(物件、抽象、封裝、繼承、多型)

前言:今天第一次上C++課程。根據老師的所講內容進度,記錄C++知識!!! 第一章 問題一:什麼是面向物件程式設計? 面向物件程式設計是一種新的程式設計範型。主要特徵是:程式=物件+訊息 面向物件程式設計的

linuxC開發多執行程式

轉:https://blog.csdn.net/lingfemg721/article/details/6574804   linux下用C開發多執行緒程式,Linux系統下的多執行緒遵循POSIX執行緒介面,稱為pthread。   #

補習:C# 面向物件三大特性:封裝、繼承、多型

C# 面向物件三大基本特性 封裝、繼承、多型 1、封裝 隱藏物件的屬性和實現細節,僅對外公開介面,控制在程式中屬性的讀取和修改的訪問級別。 C# 封裝根據具體的需要,設定使用者的訪問許可權,並通過 訪問修飾符 來實現。 一個 訪問修飾符 定義了一個類成員的範圍和可

C++設計模式-面向物件程式設計要點以及封裝性特點

目錄   1.面向物件程式設計要點 2.單使用封裝性的例子   1.面向物件程式設計要點 面向物件程式設計要注意什麼: 注意3點: 1.可維護性; 2.可擴充套件性; 3.可複用性; 4.靈活性好; 注意:要儘可能的避免重複; 要求業務邏輯與介面分

執行基本封裝

執行緒類 面向物件風格: 通過子類重寫run方法 實現多型 從而實現依賴反轉 但我們要提供抽象類和介面 將run()方法和startThread()方法宣告的私有的 其實本沒有有必要宣告為公有的 我們在start------>startThread ----

python中的面向物件學習以及封裝(這篇文章初學者一定要好好看)

這篇文章對於初學者可以很有效的理解面對過程、面對物件 一、首先介紹一下面向過程和麵向物件的比較: 面向過程 VS 面向物件 程式設計正規化 程式設計是程式設計師用特定的語法+資料結構+演算法組成的程式碼來告訴計算機如何執行任務的過程 , 一個程式是程式設計師為了得到一個任務結果而

c#面向物件程式設計—— 彈出窗體以及新建窗體的返回值,圖片匯入,退出問題

新建窗體類: 在form1的載入事件中加入以下語句: private void Form1_Load(object sender, EventArgs e) { Message mes = new Message();

Java基礎複習第七天——面向物件思想、物件封裝、構造方法、JavaBean

目錄 一 面向物件思想 1.概述 2.面向物件的三大特徵          3.類和物件 4.類和物件的關係 5.類的定義 6.成員變數和區域性變數 7.物件的使用格式 8.物件記憶體圖 二.封裝

利用C++11實現執行task的簡單封裝

#include <functional> #include <thread> #include <type_traits> /*Compile only if 'F' is callable. F maybe function, la

C#面向物件 |多型之抽象案例

使用抽象類結構實現 NPC 模組 在遊戲中會出現很多種不同用途的 NPC,這些 NPC有各自的存在價值和作用,同時又具備一些共性的東西。在開發 NPC 系統時,往往需要提取共性,獨立出一個父類,然後子類繼承父類,實現不同作用的 NPC。 分析 任務 NPC,商販 NPC,鐵匠 NPC,三種 NPC

c++ 網路程式設計(九)TCP/IP LINUX/windows下 多執行超詳細教程 以及 多執行實現服務端

#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> #include <process.h> #include <winsock2.h> #include <win