国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

Linux知識點 -- Linux多線程(四)

這篇具有很好參考價值的文章主要介紹了Linux知識點 -- Linux多線程(四)。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

Linux知識點 – Linux多線程(四)


一、線程池

1.概念

一種線程使用模式。線程過多會帶來調(diào)度開銷,進而影響緩存局部性和整體性能。而線程池維護著多個線程,等待著監(jiān)督管理者分配可并發(fā)執(zhí)行的任務。這避免了在處理短時間任務時創(chuàng)建與銷毀線程的代價。線程池不僅能夠保證內(nèi)核的充分利用,還能防止過分調(diào)度。可用線程數(shù)量應該取決于可用的并發(fā)處理器、處理器內(nèi)核、內(nèi)存、網(wǎng)絡sockets等的數(shù)量。

  • 預先申請資源,用空間換時間;
  • 預先申請一批線程,任務到來就處理;
  • 線程池就是一個生產(chǎn)消費模型;

2.實現(xiàn)

thread.hpp
線程封裝:

#pragma once

#include<iostream>
#include<string>
#include<functional>
#include<cstdio>

typedef void* (*fun_t)(void*); // 定義函數(shù)指針類型,后面回調(diào)

class ThreadData  // 線程信息結(jié)構(gòu)體
{
public:
    void* _args;
    std::string _name;
};

class Thread
{
public:
    Thread(int num, fun_t callback, void* args)
        : _func(callback)
    {
        char nameBuffer[64];
        snprintf(nameBuffer, sizeof(nameBuffer), "Thread-%d", num);
        _name = nameBuffer;

        _tdata._args = args;
        _tdata._name = _name;
    }

    void start() // 創(chuàng)建線程
    {
        pthread_create(&_tid, nullptr, _func, (void*)&_tdata); // 直接將_tdata作為參數(shù)傳給回調(diào)函數(shù)
    }

    void join() // 線程等待
    {
        pthread_join(_tid, nullptr);
    }

    std::string name()
    {
        return _name;
    }

    ~Thread()
    {}

private:
    std::string _name;
    fun_t _func;
    ThreadData _tdata;
    pthread_t _tid;
};

lockGuard.hpp
鎖的封裝,構(gòu)建對象時直接加鎖,對象析構(gòu)時自動解鎖;

#pragma once

#include <iostream>
#include <pthread.h>

class Mutex
{
public:
    Mutex(pthread_mutex_t *mtx)
        : _pmtx(mtx)
    {
    }

    void lock()
    {
        pthread_mutex_lock(_pmtx);
    }

    void unlock()
    {
        pthread_mutex_unlock(_pmtx);
    }

    ~Mutex()
    {}

private:
    pthread_mutex_t *_pmtx;
};


class lockGuard
{
public:
    lockGuard(pthread_mutex_t *mtx)
        : _mtx(mtx)
    {
        _mtx.lock();
    }

    ~lockGuard()
    {
        _mtx.unlock();
    }
private:
    Mutex _mtx;
};

log.hpp

#pragma once

#include<iostream>
#include<cstdio>
#include<cstdarg>
#include<ctime>
#include<string>

//日志級別
#define DEBUG 0
#define NORMAL 1
#define WARNING 2
#define ERROR 3
#define FATAL 4

const char* gLevelMap[] = {
    "DEBUG",
    "NORMAL",
    "WARNING",
    "ERROR",
    "FATAL"
};

#define LOGFILE "./threadpool.log"

//完整的日志功能,至少需要:日志等級 時間 支持用戶自定義(日志內(nèi)容,文件行,文件名)

void logMessage(int level, const char* format, ...)
{
#ifndef DEBUG_SHOW
    if(level == DEBUG) return;
#endif

    char stdBuffer[1024];//標準部分
    time_t timestamp = time(nullptr);
    snprintf(stdBuffer, sizeof(stdBuffer), "[%s] [%ld] ", gLevelMap[level], timestamp);

    char logBuffer[1024];//自定義部分
    va_list args;
    va_start(args, format);
    vsnprintf(logBuffer, sizeof(logBuffer), format, args);
    va_end(args);

    FILE* fp = fopen(LOGFILE, "a");
    fprintf(fp, "%s %s\n", stdBuffer, logBuffer);
    fclose(fp);
}
  • 注:
    (1)提取可變參數(shù)
    Linux知識點 -- Linux多線程(四),Linux,linux,運維,服務器
    使用宏來提取可變參數(shù):
    Linux知識點 -- Linux多線程(四),Linux,linux,運維,服務器
    將可變參數(shù)格式化打印到對應地點:
    Linux知識點 -- Linux多線程(四),Linux,linux,運維,服務器
    format是打印的格式;
    Linux知識點 -- Linux多線程(四),Linux,linux,運維,服務器
    (2)條件編譯:
    Linux知識點 -- Linux多線程(四),Linux,linux,運維,服務器
    條件編譯,不想調(diào)試的時候,就不加DEBUG宏,不打印日志信息;
    Linux知識點 -- Linux多線程(四),Linux,linux,運維,服務器
    -D:在命令行定義宏 ;

threadPool.hpp

線程池封裝:

#include "thread.hpp"
#include <vector>
#include <queue>
#include <unistd.h>
#include "log.hpp"
#include "Task.hpp"
#include "lockGuard.hpp"

const int g_thread_num = 3;

template <class T>
class ThreadPool
{
public:
    pthread_mutex_t *getMutex()
    {
        return &_lock;
    }

    bool isEmpty()
    {
        return _task_queue.empty();
    }

    void waitCond()
    {
        pthread_cond_wait(&_cond, &_lock);
    }

    T getTask()
    {
        T t = _task_queue.front();
        _task_queue.pop();
        return t;
    }

    ThreadPool(int thread_num = g_thread_num)
        : _num(thread_num)
    {
        pthread_mutex_init(&_lock, nullptr);
        pthread_cond_init(&_cond, nullptr);
        for (int i = 1; i <= _num; i++)
        {
            _threads.push_back(new Thread(i, routine, this));
            // 線程構(gòu)造傳入的this指針,是作為ThreadData結(jié)構(gòu)體的參數(shù)的,ThreadData結(jié)構(gòu)體才是routine回調(diào)函數(shù)的參數(shù)
            // 由于由于回調(diào)函數(shù)是靜態(tài)成員,無法訪問非靜態(tài)成員
            // 這里傳入this指針是用來在回調(diào)函數(shù)中給訪問非靜態(tài)成員的

        }
    }

    void run()
    {
        for (auto &iter : _threads)
        {
            iter->start();
            logMessage(NORMAL, "%s %s", iter->name().c_str(), "啟動成功");
        }
    }

    // 消費過程:線程調(diào)用回調(diào)函數(shù)取任務就是所謂的消費過程,訪問了臨界資源,需要加鎖
    static void *routine(void *args) //由于這個函數(shù)是類內(nèi)成員,參數(shù)是有this指針的,參數(shù)類型不對,因此多線程回調(diào)的時候無法識別
                                     //需要設(shè)置成static靜態(tài)成員,才可以回調(diào)
    {
        ThreadData *td = (ThreadData *)args;
        ThreadPool<T> *tp = (ThreadPool<T> *)td->_args; // 拿到this指針,通過本對象的this指針來調(diào)用成員函數(shù)
        while (true)
        {
            T task;
            {
                lockGuard lockguard(tp->getMutex());
                while (tp->isEmpty())
                {
                    tp->waitCond();
                }
                // 讀取任務
                task = tp->getTask();
                // 任務隊列是共享的,將任務從共享空間,拿到私有空間
            }
            task(td->_name); // 處理任務
        }
    }

    void pushTask(const T &task)
    {
        lockGuard lockguard(&_lock); // 訪問臨界資源,需要加鎖
        _task_queue.push(task);
        pthread_cond_signal(&_cond); // 推送任務后,發(fā)送信號,讓進程處理
    }

    ~ThreadPool()
    {
        for (auto &iter : _threads)
        {
            iter->join();
            delete iter;
        }
        pthread_mutex_destroy(&_lock);
        pthread_cond_destroy(&_cond);
    }

private:
    std::vector<Thread *> _threads; // 線程池
    int _num;
    std::queue<T> _task_queue; // 任務隊列
    pthread_mutex_t _lock;     // 鎖
    pthread_cond_t _cond;      // 條件變量
};
  • 注:
    (1)如果回調(diào)函數(shù)routine放在thread類里面,由于成員函數(shù)會默認傳this指針,因此參數(shù)識別的時候可能會出錯,所以需要設(shè)置成靜態(tài)成員;Linux知識點 -- Linux多線程(四),Linux,linux,運維,服務器
    Linux知識點 -- Linux多線程(四),Linux,linux,運維,服務器
    (2)如果設(shè)置成靜態(tài)類內(nèi)方法,這個函數(shù)只能使用靜態(tài)成員,而不能使用其他類內(nèi)成員;
    可以讓routine函數(shù)拿到整體對象,在構(gòu)造線程的時候,routine的參數(shù)傳入this指針;

    Linux知識點 -- Linux多線程(四),Linux,linux,運維,服務器
    在構(gòu)造函數(shù)的初始化列表中是參數(shù)的初始化,在下面的函數(shù)體中是賦值的過程,因此在函數(shù)體中對象已經(jīng)存在了,就可以使用this指針了;
    (3)類內(nèi)公有接口讓靜態(tài)成員函數(shù)routine通過this指針能夠訪問類內(nèi)成員;
    Linux知識點 -- Linux多線程(四),Linux,linux,運維,服務器
    testMain.cc
#include"threadPool.hpp"
#include"Task.hpp"
#include<ctime>
#include<cstdlib>
#include<iostream>
#include<unistd.h>

int main()
{
    srand((unsigned long)time(nullptr) ^ getpid());

    ThreadPool<Task>* tp = new ThreadPool<Task>();
    tp->run();

    while(true)
    {
        //生產(chǎn)的時候,只做任務要花時間
        int x = rand()%100 + 1;
        usleep(7756);
        int y = rand()%30 + 1;
        Task t(x, y, [](int x, int y)->int{
            return x + y;
        });

        logMessage(DEBUG, "制作任務完成:%d+%d=?", x, y);

        //推送任務到線程池中
        tp->pushTask(t);

        sleep(1);
    }

    return 0;
}

運行結(jié)果:
Linux知識點 -- Linux多線程(四),Linux,linux,運維,服務器

3.單例模式的線程池

threadPool.hpp

#include "thread.hpp"
#include <vector>
#include <queue>
#include <unistd.h>
#include "log.hpp"
#include "Task.hpp"
#include "lockGuard.hpp"

const int g_thread_num = 3;

template <class T>
class ThreadPool
{
public:
    pthread_mutex_t *getMutex()
    {
        return &_lock;
    }

    bool isEmpty()
    {
        return _task_queue.empty();
    }

    void waitCond()
    {
        pthread_cond_wait(&_cond, &_lock);
    }

    T getTask()
    {
        T t = _task_queue.front();
        _task_queue.pop();
        return t;
    }

//單例模式線程池:懶漢模式
private:
    //構(gòu)造函數(shù)設(shè)為私有
    ThreadPool(int thread_num = g_thread_num)
        : _num(thread_num)
    {
        pthread_mutex_init(&_lock, nullptr);
        pthread_cond_init(&_cond, nullptr);
        for (int i = 1; i <= _num; i++)
        {
            _threads.push_back(new Thread(i, routine, this));
            // 線程構(gòu)造傳入的this指針,是作為ThreadData結(jié)構(gòu)體的參數(shù)的,ThreadData結(jié)構(gòu)體才是routine回調(diào)函數(shù)的參數(shù)
        }
    }

    ThreadPool(const ThreadPool<T> &other) = delete;
    const ThreadPool<T>& operator=(const ThreadPool<T> &other) = delete;

public:
    //創(chuàng)建單例對象的類內(nèi)靜態(tài)成員函數(shù)
    static ThreadPool<T>* getThreadPool(int num = g_thread_num)
    {
        //在這里再加上一個條件判斷,可以有效減少未來必定要進行的加鎖檢測的問題
        //攔截大量的在已經(jīng)創(chuàng)建好單例的時候,剩余線程請求單例而直接申請鎖的行為
        if(nullptr == _thread_ptr)
        {
            //加鎖
            lockGuard lockguard(&_mutex);
            //未來任何一個線程想要獲取單例,都必須調(diào)用getThreadPool接口
            //一定會存在大量的申請鎖和釋放鎖的行為,無用且浪費資源
            if(nullptr == _thread_ptr)
            {
                _thread_ptr = new ThreadPool<T>(num);
            }
        }
        return _thread_ptr;
    }

    void run()
    {
        for (auto &iter : _threads)
        {
            iter->start();
            logMessage(NORMAL, "%s %s", iter->name().c_str(), "啟動成功");
        }
    }

    // 消費過程:線程調(diào)用回調(diào)函數(shù)取任務就是所謂的消費過程,訪問了臨界資源,需要加鎖
    static void *routine(void *args)
    {
        ThreadData *td = (ThreadData *)args;
        ThreadPool<T> *tp = (ThreadPool<T> *)td->_args; // 拿到this指針
        while (true)
        {
            T task;
            {
                lockGuard lockguard(tp->getMutex());
                while (tp->isEmpty())
                {
                    tp->waitCond();
                }
                // 讀取任務
                task = tp->getTask();
                // 任務隊列是共享的,將任務從共享空間,拿到私有空間
            }
            task(td->_name); // 處理任務
        }
    }

    void pushTask(const T &task)
    {
        lockGuard lockguard(&_lock); // 訪問臨界資源,需要加鎖
        _task_queue.push(task);
        pthread_cond_signal(&_cond); // 推送任務后,發(fā)送信號,讓進程處理
    }

    ~ThreadPool()
    {
        for (auto &iter : _threads)
        {
            iter->join();
            delete iter;
        }
        pthread_mutex_destroy(&_lock);
        pthread_cond_destroy(&_cond);
    }

private:
    std::vector<Thread *> _threads; // 線程池
    int _num;
    std::queue<T> _task_queue; // 任務隊列

    static ThreadPool<T>* _thread_ptr;
    static pthread_mutex_t _mutex;

    pthread_mutex_t _lock;     // 鎖
    pthread_cond_t _cond;      // 條件變量
};

//靜態(tài)成員在類外初始化
template<class T>
ThreadPool<T>* ThreadPool<T>::_thread_ptr = nullptr;

template<class T>
pthread_mutex_t ThreadPool<T>::_mutex = PTHREAD_MUTEX_INITIALIZER;

Linux知識點 -- Linux多線程(四),Linux,linux,運維,服務器
Linux知識點 -- Linux多線程(四),Linux,linux,運維,服務器
多線程同時調(diào)用單例過程,由于創(chuàng)建過程是非原子的,有可能被創(chuàng)建多個對象,是非線程安全的;
需要對創(chuàng)建對象的過程加鎖,就可以保證在多線程場景當中獲取單例對象;
但是未來任何一個線程想調(diào)用單例對象,都必須調(diào)用這個成員函數(shù),就會存在大量申請和釋放鎖的行為;
可以在之間加一個對單例對象指針的判斷,若不為空,就不進行對象創(chuàng)建;

Linux知識點 -- Linux多線程(四),Linux,linux,運維,服務器
testMain.cc

#include"threadPool.hpp"
#include"Task.hpp"
#include<ctime>
#include<cstdlib>
#include<iostream>
#include<unistd.h>

int main()
{
    srand((unsigned long)time(nullptr) ^ getpid());

    //ThreadPool<Task>* tp = new ThreadPool<Task>();
    //tp->run();    
    ThreadPool<Task>::getThreadPool()->run();//創(chuàng)建單例對象

    

    while(true)
    {
        //生產(chǎn)的時候,只做任務要花時間
        int x = rand()%100 + 1;
        usleep(7756);
        int y = rand()%30 + 1;
        Task t(x, y, [](int x, int y)->int{
            return x + y;
        });

        logMessage(DEBUG, "制作任務完成:%d+%d=?", x, y);

        //推送任務到線程池中
        ThreadPool<Task>::getThreadPool()->pushTask(t);

        sleep(1);
    }

    return 0;
}

運行結(jié)果:
Linux知識點 -- Linux多線程(四),Linux,linux,運維,服務器

二、STL、智能指針和線程安全

1.STL的容器是否是線程安全的

不是;
原因是, STL的設(shè)計初衷是將性能挖掘到極致,而一旦涉及到加鎖保證線程安全,會對性能造成巨大的影響;
而且對于不同的容器,加鎖方式的不同,性能可能也不同(例如hash表的鎖表和鎖桶)。
因此STL默認不是線程安全。如果需要在多線程環(huán)境下使用,往往需要調(diào)用者自行保證線程安全。

2.智能指針是否是線程安全的

對于unique_ ptr,由于只是在當前代碼塊范圍內(nèi)生效,因此不涉及線程安全問題;
對于shared_ptr,多個對象需要共用一個引用計數(shù)變量,所以會存在線程安全問題.但是標準庫實現(xiàn)的時候考慮到了這個問題,基于原子操作(CAS)的方式保證shared_ptr 能夠高效,原子的操作弓|用計數(shù);

三、其他常見的各種鎖

  • 悲觀鎖:在每次取數(shù)據(jù)時,總是擔心數(shù)據(jù)會被其他線程修改,所以會在取數(shù)據(jù)前先加鎖(讀鎖,寫鎖,行鎖等) ,當其他線程想要訪問數(shù)據(jù)時,被阻塞掛起;
  • 樂觀鎖:每次取數(shù)據(jù)時候,總是樂觀的認為數(shù)據(jù)不會被其他線程修改,因此不上鎖。但是在更新數(shù)據(jù)前,會判斷其他數(shù)據(jù)在更新前有沒有對數(shù)據(jù)進行修改。主要采用兩種方式:版本號機制和CAS操作;
    CAS操作:當需要更新數(shù)據(jù)時,判斷當前內(nèi)存值和之前取得的值是否相等。如果相等則用新值更新。若不等則失敗,失敗則重試,一般是一個自旋的過程,即不斷重試;
  • 自旋鎖
    臨界資源就緒的時間決定了線程等待的策略;
    不斷檢測資源是否就緒就是自旋(輪詢檢測);
    自旋鎖本質(zhì)就是通過不斷檢測鎖狀態(tài),來檢測資源是否就緒的方案

    Linux知識點 -- Linux多線程(四),Linux,linux,運維,服務器
    互斥鎖是檢測到資源未就緒,就掛起線程;
    臨界資源就緒的時間決定了使用哪種鎖;

四、讀者寫者問題

1.讀寫鎖

在編寫多線程的時候,有一種情況是十分常見的。那就是,有些公共數(shù)據(jù)修改的機會比較少,相比較改寫,它們讀的機會反而高的多。通常而言,在讀的過程中,往往伴隨著查找的操作,中間耗時長。給這種代碼段加鎖,會極大地降低我們程序的效率。那么有沒有一種方法,可以專門]處理這種多讀少寫的情況呢?有,那就是讀寫鎖。

  • 讀者寫者模型與生產(chǎn)消費模型的本質(zhì)區(qū)別:
    生產(chǎn)消費模型中消費者會取走數(shù)據(jù),而讀者寫者模型中讀者不會取走數(shù)據(jù);

  • 讀鎖的優(yōu)先級高

2.讀寫鎖接口

  • 初始化:
    Linux知識點 -- Linux多線程(四),Linux,linux,運維,服務器

  • 讀者加鎖:
    Linux知識點 -- Linux多線程(四),Linux,linux,運維,服務器

  • 寫者加鎖:

Linux知識點 -- Linux多線程(四),Linux,linux,運維,服務器
生產(chǎn)消費模型中,生產(chǎn)者和消費者的地位是對等的,這樣才能達到最高效的狀態(tài)
而讀寫者模型中,寫者只有在讀者全部退出的時候才能寫,是讀者優(yōu)先的,這樣就會發(fā)生寫者饑餓問題;
讀者寫者問題中讀鎖的優(yōu)先級高,是因為這種模型的應用場景為:數(shù)據(jù)的讀取頻率非常高,而被修改的頻率特別低,這樣有助于提升效率;
文章來源地址http://www.zghlxwxcb.cn/news/detail-693788.html

到了這里,關(guān)于Linux知識點 -- Linux多線程(四)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權(quán),不承擔相關(guān)法律責任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務器費用

相關(guān)文章

  • Linux相關(guān)知識點

    Linux是一套免費使用和自由傳播的類Unix操作系統(tǒng),是一個基于POSIX和UNIX的多用戶、多任務、支持多線程和多CPU的操作系統(tǒng)。它能運行主要的UNIX工具軟件、應用程序和網(wǎng)絡協(xié)議。它支持32位和64位硬件。 Linux內(nèi)核 是一個Linux系統(tǒng)的內(nèi)核,而不是一個操作系統(tǒng) Linux操作系統(tǒng) 紅帽操

    2024年02月11日
    瀏覽(22)
  • Linux基礎(chǔ)知識點2

    Linux基礎(chǔ)知識點2

    Linux基礎(chǔ)知識?適合有Linux基礎(chǔ)的人群進行復習。 禁止轉(zhuǎn)載! 文件管理與常用命令 Linux的文件的組成部分: ?????? 文件名 、 inode (i節(jié)點)和 block (真正存數(shù)據(jù)的區(qū)域)。 查看某個文件的屬性: ?????????? ls -lh???? #可看到有類似”-rw-r--r--”的屬性符號?????? ??? 第

    2024年02月09日
    瀏覽(26)
  • Linux知識點 -- 進程概念(補充)

    Linux知識點 -- 進程概念(補充)

    在用戶每次使用malloc等函數(shù)在進程的堆區(qū)申請地址時,用戶只需要指定空間的大小,并且會得到一個起始地址,而不會得到結(jié)束地址; 因為 堆區(qū)的結(jié)構(gòu)都是由 vm_area_struct 管理的,每次malloc都會申請一個該結(jié)構(gòu)體; malloc在堆上申請空間時,只需要知道起始地址,不需要知道結(jié)

    2024年02月13日
    瀏覽(95)
  • Linux知識點 -- 網(wǎng)絡基礎(chǔ)(一)

    Linux知識點 -- 網(wǎng)絡基礎(chǔ)(一)

    獨立模式:計算機之間相互獨立 網(wǎng)絡互聯(lián):多臺計算機連接在一起,完成數(shù)據(jù)共享 局域網(wǎng)LAN:計算機數(shù)量更多了,通過交換機和路由器連接在一起: 廣域網(wǎng)WAN:將遠隔千里的計算機都連接在一起 注:局域網(wǎng)和廣域網(wǎng)只有規(guī)模上的差別; OSI (Open System Interconnection,開放系統(tǒng)互

    2024年02月11日
    瀏覽(23)
  • 【知識點】linux下啟動tomcat

    切換到tomcat安裝目錄下的bin目錄。 如不知安裝目錄,可以使用: 查找。 進入bin目錄,通過命令啟動。 (該方式是直接后臺啟動。當關(guān)閉linux會話窗口,tomcat服務也隨之關(guān)閉。) (該方式啟動,會顯示日志,不能輸入linux命令。當關(guān)閉linux會話窗口,tomcat服務也隨之關(guān)閉。)

    2024年02月08日
    瀏覽(22)
  • 關(guān)于Linux同步機制知識點整理

    關(guān)于Linux同步機制知識點整理

    在Linux系統(tǒng)中,同步機制是操作系統(tǒng)中非常重要的一部分,以下是一些基本要點: 互斥鎖 互斥鎖是一種「獨占鎖」,比如當線程 A 加鎖成功后,此時互斥鎖已經(jīng)被線程 A 獨占了,只要線程 A 沒有釋放手中的鎖,線程 B 加鎖就會失敗,失敗的線程B于是就會釋放 CPU 讓給其他線程

    2024年02月11日
    瀏覽(21)
  • Linux知識點 -- 基礎(chǔ)IO(二)

    Linux知識點 -- 基礎(chǔ)IO(二)

    在上面的代碼中,fprintf本來是向stdout中打印的,但是stdout關(guān)閉了,實際上fprintf事項fd是1的文件中打印,這里log.txt的fd就是1; 運行結(jié)果為: 這就叫做 輸出重定向 ; 上面的代碼將stdout關(guān)閉了,并打開log.txt文件,則log.txt文件的fd就是1; 在系統(tǒng)中,stdout就代表著fd為1,所以默

    2024年02月15日
    瀏覽(21)
  • Linux知識點 -- 進程間通信(二)

    Linux知識點 -- 進程間通信(二)

    先在內(nèi)存中申請空間,然后將這段空間映射到不同進程的地址空間中,這就叫做共享內(nèi)存; 一般都是映射在進程的堆棧之間的共享區(qū); 共享內(nèi)存不屬于任何一個進程,它屬于操作系統(tǒng); 操作系統(tǒng)對共享內(nèi)存的管理,是先描述再組織,先通過內(nèi)核數(shù)據(jù)結(jié)構(gòu)描述共享內(nèi)存的屬性

    2024年02月14日
    瀏覽(101)
  • Linux網(wǎng)絡編程(一-網(wǎng)絡相關(guān)知識點)

    Linux網(wǎng)絡編程(一-網(wǎng)絡相關(guān)知識點)

    目錄 ?? 一、網(wǎng)絡相關(guān)知識簡介 二、網(wǎng)絡協(xié)議的分層模型 2.1 OSI七層模型 2.2 TCP/IP五層模型 2.3 協(xié)議層報文間的封裝與拆封? 三、IP協(xié)議 3.1 MAC地址? 3.2 IP地址 3.3 MAC地址與IP地址區(qū)別 互聯(lián)網(wǎng)通信的本質(zhì)是數(shù)字通信,任何數(shù)字通信都離不開通信協(xié)議的制定,通信設(shè)備只有按照約定

    2024年01月24日
    瀏覽(27)
  • 運維知識點-Sqlite

    運維知識點-Sqlite

    2024年01月16日
    瀏覽(22)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包