C++線程


本着能用STL就不用其他庫的原則,本文以c++11的std::thread作為接口開發。【VS2010不支持C++11的線程,VS2013支持】

 

 

根據我另一個帖子,線程函數只能是全局或者靜態的。https://www.cnblogs.com/judes/p/5921104.html

全局函數:只能訪問全局變量,需要注意加互斥鎖

靜態函數:只能訪問靜態變量

 

項目中常常需要線程訪問類中的成員,本文也重點實現這個功能,下面提供兩種方式。使用多線程賣票舉例:

賣票頭文件:

#pragma once
#include <thread>
#include <mutex>
#include <Windows.h>
using namespace std;
class SellTickts
{
public:
    void SellTickts::seller_1();
    void SellTickts::seller_2();
    int ticketNum = 10;
    mutex Mutex;
public:
    SellTickts();
    virtual ~SellTickts();
    void sell();
    friend void sell(void* param);
};

賣票源文件:

#include "stdafx.h"
#include "SellTickts.h"


SellTickts::SellTickts()
{

}


SellTickts::~SellTickts()
{

}
//函數名稱:售票員1
//函數作用:NULL
//函數參數:NULL
//函數返回值:NULL
//函數信息:NULL
//備注:NULL
void SellTickts::seller_1()
{
    for (;;)
    {
        Mutex.lock();
        if (ticketNum == 0)
        {
            break;
        }
        else
        {

            ticketNum--;
            printf("Seller_1 sold a ticket, remains %d.\n", ticketNum);
            if (ticketNum == 0)
            {
                printf("Tickets has been sold out.\n");
                break;
            }
        }        
        Mutex.unlock();
Sleep(100); } }
//函數名稱:售票員2 //函數作用:NULL //函數參數:NULL //函數返回值:NULL //函數信息:NULL //備注:NULL void SellTickts::seller_2() { for (;;) { Mutex.lock(); if (ticketNum == 0) { break; } else { ticketNum--; printf("Seller_2 sold a ticket, remains %d.\n", ticketNum); if (ticketNum == 0) { printf("Tickets has been sold out.\n"); break; } } Mutex.unlock();
Sleep(100); } }
//函數名稱:類函數售票 //函數作用:NULL //函數參數:NULL //函數返回值:NULL //函數信息:NULL //備注:NULL void SellTickts::sell() { printf("class sell.\n"); thread thread1(&SellTickts::seller_1,this); thread thread2(&SellTickts::seller_2,this); thread1.detach(); thread2.detach(); } //函數名稱:友元函數售票 //函數作用:NULL //函數參數:NULL //函數返回值:NULL //函數信息:NULL //備注:NULL void sell(void* param) { printf("friend sell.\n"); SellTickts* pThis = (SellTickts*)param; thread thread1(&SellTickts::seller_1, pThis); thread thread2(&SellTickts::seller_2, pThis); thread1.detach(); thread2.detach(); }

main函數:

// ControlTest.cpp : 定義控制台應用程序的入口點。
//
void test();
#include "stdafx.h"
#include "SellTickts.h"
int _tmain(int argc, _TCHAR* argv[])
{
    SellTickts sellTickets;
 sellTickets.sell();//類函數作為函數入口
sell(
&sellTickets);//友元函數作為函數入口

   thread t(test);//全局函數作為函數入口
t.detach();

thread t1(&SellTickets::seller_1,this);//類外部使用類函數作為函數入口
t1.detach();
) while (true) { } return 0; }

關於友元函數的分析:https://www.cnblogs.com/judes/p/8202602.html

 

分析:

1、類函數作為線程入口:thread thread1(&SellTickts::seller_1,this);

 

 第一個參數是函數的地址,這里有個概念:無論類都有多少個對象,這些對象所使用的類函數都是同一個地址,只有屬性地址不同。

class A{
       int temp;
       void fun();
};

無論A類有多少個對象,這些對象所調用fun函數時,都是用的同一個地址,這個地址在類A定義的時候就有了;但是每個對象中的屬性test地址都是不同的。那么fun函數如何區分當前是被哪個對象調用的呢?fun函數有一個默認參數this,當對象聲明時,就有了一個對應的this,誰調用fun,就把誰的this傳進去,這樣就沒問題了。

注意:如果想要類函數的地址,需要&類::函數,不能&對象::函數,這也是我剛開始不理解的地方。

第二個參數時this,是因為類函數都有默認參數this,所以這里必須傳遞參數this進去,否則編譯出錯。

 

 

2、友元函數作為線程入口:thread thread1(&SellTickts::seller_1, pThis);

 其實原理一樣,不同的就是友元函數滅有默認this參數,需要程序員手動放入類指針。

 

 

3、使用全局函數作為線程入口:thread t(test);

不知道為啥這里不使用函數的地址

 

 

ps:怎么獲取線程id和程序id

直接使用thread的get_id函數返回的是個thread類的內部類,不方便獲取id,可以使用各平台自己的api

#ifndef __linux__
#include "windows.h"
#else
#include "unistd.h"
#endif

#ifndef __linux__
printf("now pid is %d \n", GetCurrentProcessId());
printf("now tid is %d \n", GetCurrentThreadId());

#else
printf("now pid is %d \n", getpid());
printf("now tid is %d \n", gettid());
#endif

 

 

ps:關於多線程調用同一全局函數的理解【轉:https://www.cnblogs.com/liangjf/p/9801496.html】

每個線程有自己的堆棧空間,而全局函數是只讀的,當多個線程使用這個函數的時候,應該會把函數功能復制一份到自己的堆棧,然后函數內部的變量都放在自己的空間內,這樣就互不影響了。

當然如果訪問的是同一個全局變量,加互斥鎖就可以了。

 

 

 

ps:thread::detach和join的區別

join()操作是在std::thread t(func)后“某個”合適的地方調用,其作用是回收對應創建的線程的資源,避免造成資源的泄露。detach()操作是在std::thread t(func)后馬上調用,用於把被創建的線程與做創建動作的線程分離,分離的線程變為后台線程,其后,創建的線程的“死活”就與其做創建動作的線程無關,它的資源會被init進程回收。

主要談join:

void test()
{
}

bool do_other_things()
{
}

int main()
{
    std::thread t(test);
    int ret = do_other_things();
    if(ret == ERROR) {
        return -1;
    }

    t.join();
    return 0;
}

可能執行不到join

解決:

class mythread {
private:
    std::thread &m_t;

public:
    explicit mythread(std::thread &t):m_t(t){}
    ~mythread() {
        if(t.joinable()) {
            t.join()
        }
    }

    mythread(mythread const&) = delete;
    mythread& operate=(mythread const&) = delete;
}

void test()
{
}

bool do_other_things()
{
}

int main()
{
    std::thread t(test);
    mythread q(t);

    if(do_other_things()) {
        return -1;
    }

    return 0;
}

 

 

ps:休眠

#include <thread>
#include <chrono>


std::this_thread::sleep_for(std::chrono::milliseconds(50));

 


免責聲明!

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



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