Linux C語言線程編程入門筆記

目錄

  • 開發環境準備

  • 線程基礎概念

    • 進程與線程的關系

    • 線程生命周期

  • 創建線程

  • 等待線程結束

  • 線程函數和參數

  • 互斥鎖與共享資源保護

  • 總結

開發環境準備

  • 操作系統:以 Linux 為例(Ubuntu/CentOS 等主流發行版)。請確保系統已安裝 GNU C 編譯器(gcc)。

  • 線程庫:POSIX 線程庫一般已包含在標準庫中。若未安裝,可以通過包管理器安裝對應開發包。

  • 編譯命令:編寫完成代碼后,可用 gcc 編譯,并加上線程選項。示例:

gcc -o myprog main.c -pthread

其中 -pthread(或 -lpthread)選項用于鏈接 pthread 庫?blog.csdn.net。例如出現 undefined reference to pthread_create 錯誤時,需要添加此選項。

線程基礎概念

進程與線程的關系

多個線程示意圖展示了同一進程中各線程共享的資源,如代碼段、數據段和打開的文件等?cnblogs.com。線程屬于進程,一個進程可以包含一個或多個線程?cnblogs.com。一般來說,進程是操作系統進行資源分配和調度的最小單位,而線程是程序執行的最小單位?cnblogs.com。同一進程中的多個線程共享進程的內存空間(包括代碼、數據、堆等),但各自擁有獨立的寄存器和棧空間?cnblogs.com。多個線程并發執行時,可以提高程序并行度,但也需要注意同步和互斥。

線程生命周期

如上圖所示,線程在運行過程中會經歷不同狀態。通常一個線程的生命周期包括 新建 (New)就緒 (Runnable)運行 (Running)阻塞/等待 (Blocked/Waiting)終止 (Dead) 等階段?cnblogs.com。當調用 pthread_create() 后,線程從“新建”進入“就緒”狀態;線程獲得 CPU 時間后進入“運行”狀態;如果線程調用 sleep()pthread_join() 等阻塞操作,則進入“阻塞”狀態。線程執行完畢或調用 pthread_exit() 后進入“終止”狀態?cnblogs.com。掌握這些狀態轉換有助于理解線程的調度行為和并發執行過程。

創建線程

要創建線程,使用 POSIX 線程庫提供的 pthread_create() 函數。其原型如下:

int pthread_create(pthread_t *thread,const pthread_attr_t *attr,void *(*start_routine)(void *),void *arg);
  • thread:指向 pthread_t 類型變量的指針,用于保存新創建線程的 ID。

  • attr:線程屬性,一般使用默認值 NULL

  • start_routine:線程入口函數地址(函數指針)。

  • arg:傳遞給線程函數的參數,類型為 void*

示例:創建一個線程執行簡單的打印函數。

#include <stdio.h>
#include <pthread.h>void* say_hello(void* arg) {printf("Hello from thread!\n");return NULL;
}int main() {pthread_t tid;// 創建線程,執行 say_hello 函數pthread_create(&tid, NULL, say_hello, NULL);// 等待線程結束pthread_join(tid, NULL);return 0;
}

以上代碼中,pthread_create(&tid, NULL, say_hello, NULL); 會創建一個新線程,該線程運行 say_hello 函數。主線程pthread_create 之后繼續往下執行(此例中主線程隨后調用了 pthread_join 等待子線程結束)。

等待線程結束

創建線程后,主線程和子線程是并發執行的。有時需要主線程等待子線程完成后再繼續,比如輸出結果或回收資源。此時使用 pthread_join() 函數。其原型為:

int pthread_join(pthread_t thread, void **retval);
  • 第一個參數為要等待的線程 ID;

  • 第二個參數用于獲取線程函數的返回值(可為 NULL 表示不關心返回值)。

上例中 pthread_join(tid, NULL); 會阻塞主線程,直到 tid 對應的子線程執行結束并回收其資源為止。若省略 pthread_join,主線程可能在子線程完成前就退出,導致子線程被強制終止或無法正常輸出結果。

線程函數和參數

線程入口函數必須符合 void* func(void* arg) 的形式。函數內參數類型為 void*,可以傳遞任意指針數據。在線程內部,需要根據實際類型將參數指針轉換回來。例如:

#include <stdio.h>
#include <pthread.h>void* print_num(void* arg) {int *p = (int*)arg;      // 轉換回 int* 類型printf("num = %d\n", *p);return NULL;
}int main() {pthread_t tid;int value = 42;// 將 &value 作為參數傳入線程pthread_create(&tid, NULL, print_num, &value);pthread_join(tid, NULL);return 0;
}

上例中,主線程定義了一個整數 value = 42,并將它的地址傳給子線程。子線程在 print_num 函數中把 void* 參數轉換為 int* 后,通過 *p 訪問該值并打印。注意:被傳遞的數據(如 value)在子線程訪問期間必須有效,如果是局部變量則不能在其作用域結束后再訪問。

互斥鎖與共享資源保護

多個線程同時訪問共享資源(如全局變量或共享數據結構)時,容易發生競態條件。互斥鎖 (mutex) 可以用來保護關鍵代碼區域,確保同一時間只有一個線程訪問共享資源。使用方法如下:

  1. 定義一個全局互斥鎖變量 pthread_mutex_t lock; 并初始化:

    pthread_mutex_destroy(&lock);
    
  2. 在訪問共享資源前調用 pthread_mutex_lock(&lock); 加鎖,在訪問結束后調用 pthread_mutex_unlock(&lock); 解鎖。

  3. 程序結束時釋放鎖:

pthread_mutex_destroy(&lock);

示例:兩個線程同時對全局變量 counter 進行遞增操作,使用互斥鎖保證結果正確:

#include <stdio.h>
#include <pthread.h>int counter = 0;             // 共享資源
pthread_mutex_t lock;        // 互斥鎖void* add(void* arg) {for(int i = 0; i < 100000; i++) {pthread_mutex_lock(&lock);   // 加鎖counter++;pthread_mutex_unlock(&lock); // 解鎖}return NULL;
}int main() {pthread_t t1, t2;pthread_mutex_init(&lock, NULL); // 初始化互斥鎖pthread_create(&t1, NULL, add, NULL);pthread_create(&t2, NULL, add, NULL);pthread_join(t1, NULL);pthread_join(t2, NULL);printf("counter = %d\n", counter);pthread_mutex_destroy(&lock);    // 銷毀互斥鎖return 0;
}

在上例中,若不使用鎖,則兩個線程可能會同時讀寫 counter 導致丟失更新。通過加鎖,每次只有一個線程進入臨界區 counter++,最終輸出的 counter 值才是預期的 200000

總結

本文介紹了在 Linux 下使用 C 語言進行多線程編程的入門知識。從環境準備、編譯選項,到線程基本概念(進程與線程的區別、線程生命周期)、以及線程的創建、等待和參數傳遞方法,都做了簡單說明,并給出了最基本的代碼示例。最后還演示了使用 互斥鎖 來保護共享資源的示例。整體思路清晰、示例簡潔,適合 C 語言初學者閱讀。學習多線程編程時,要特別關注線程安全和并發問題,并熟練掌握 POSIX 線程庫的常用函數。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/80142.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/80142.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/80142.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

levelDB的數據查看(非常詳細)

起因:.net大作業天氣預報程序(WPF)答辯時&#xff0c;老師問怎么維持數據持久性的&#xff0c;啟動時加載的數據存在哪里&#xff0c;我明白老師想考的應該是json文件的解析&#xff08;正反&#xff09;&#xff0c;半天沒答上來存那個文件了&#xff08;老師默認這個文件是自…

數據分析怎么做?高效的數據分析方法有哪些?

目錄 一、數據分析的對象和目的 &#xff08;一&#xff09;數據分析的常見對象 &#xff08;二&#xff09;數據分析的目的 二、數據分析怎么做&#xff1f; &#xff08;一&#xff09;明確問題 &#xff08;二&#xff09;收集數據 &#xff08;三&#xff09;清洗和…

手寫 Vue 源碼 === 完善依賴追蹤與觸發更新

目錄 依賴收集的完整實現 trackEffects:建立雙向依賴關系 觸發更新的完整實現 完整的響應式流程 為什么使用 Map 而不是 Set? 總結 在上一篇文章中,我們介紹了 Vue3 響應式系統的基本原理和 activeEffect 的作用。現在,我們將深入探討完善后的依賴追蹤和觸發更新機制…

從代碼學習深度學習 - 區域卷積神經網絡(R-CNN)系列 PyTorch版

文章目錄 前言R-CNNFast R-CNN興趣區域匯聚層 (RoI Pooling)代碼示例:興趣區域匯聚層 (RoI Pooling) 的計算方法Faster R-CNNMask R-CNN雙線性插值 (Bilinear Interpolation) 與興趣區域對齊 (RoI Align)興趣區域對齊層的輸入輸出全卷積網絡 (FCN) 的作用掩碼輸出形狀總結前言…

18個國內wordpress主題推薦

工廠wordpress中文主題 紅藍色搭配的工廠wordpress中文主題&#xff0c;適合從事生產、加工的工廠官方網站使用。 https://www.jianzhanpress.com/?p8533 Pithy設計師wordpress網站模板 精練簡潔的wordpress模板&#xff0c;設計師或設計工作室展示型網站模板。 https://w…

低成本自動化改造技術錨點深度解析

執行摘要 本文旨在深入剖析四項關鍵的低成本自動化技術&#xff0c;這些技術為工業轉型提供了顯著的運營和經濟效益。文章將提供實用且深入的指導&#xff0c;涵蓋老舊設備聯網、AGV車隊優化、空壓機系統智能能耗管控以及此類項目投資回報率&#xff08;ROI&#xff09;的嚴謹…

Oracle — 數據管理

介紹 Oracle數據庫作為全球領先的關系型數據庫管理系統&#xff0c;其數據管理能力以高效性、安全性和智能化為核心。系統通過多維度技術實現海量數據的存儲與實時處理&#xff0c;支持高并發事務操作與復雜分析查詢&#xff0c;滿足企業關鍵業務需求。在安全領域&#xff0c;O…

【PhysUnits】3.3 SI 基礎量綱單位(units/base.rs)

一、源碼 這段代碼定義了一系列基礎物理量綱的類型別名&#xff0c;并使用標記 trait Canonical 來表示它們是國際單位制&#xff08;SI&#xff09;中的基本單位。 use crate::Dimension; use typenum::{P1, Z0};/// 標記特質&#xff0c;表示基礎量綱單位 pub trait Canoni…

硬件實操技巧記錄

本篇自用&#xff0c;防止自己忘記 焊接技巧 一般都是隨機電烙鐵錫膏組合。 拆電阻時&#xff0c;電烙鐵放在電阻上&#xff0c;加錫膏&#xff0c;這個時候熔點會降低&#xff0c;電阻更容易掉下來&#xff0c;用電烙鐵帶走&#xff1b;焊電阻時&#xff0c;一端點錫膏&…

13.thinkphp的Session和cookie

一&#xff0e;Session 1. 在使用Session之前&#xff0c;需要開啟初始化&#xff0c;在中間件文件middleware.php&#xff1b; // Session 初始化 \think\middleware\SessionInit::class 2. TP6.0不支持原生$_SESSION的獲取方式&#xff0c;也不支持session_開頭的函數&…

TensorFlow中數據集的創建

目錄 前言示例示例1示例2示例3示例4 前言 TensorFlow 的 tf.data.Dataset API 提供了一種靈活且高效的方式來加載和預處理數據。它可以輕松處理大規模數據集&#xff0c;并支持多種數據源格式。 所有數據集相關的內容都在tf.data中&#xff0c;from_tensor_slices&#xff1a;…

第十六章,網絡型攻擊防范技術

網絡攻擊介紹 網絡攻擊 --- 指的是入侵或破壞網絡上的服務器 ( 主機 ) &#xff0c;盜取服務器的敏感數據或占用網絡帶寬。 網絡攻擊分類&#xff1a; 流量型攻擊 網絡層攻擊 應用層攻擊 單包攻擊 畸形報文攻擊 --- 向目標主機發送有缺陷的IP報文&#xff0c;使得目標在…

服務器不備案有影響嗎

在當今數字化的時代&#xff0c;服務器成為了眾多企業和個人開展業務、展示自我的重要工具。然而&#xff0c;有一個問題常常被忽視&#xff0c;那就是服務器不備案到底有沒有影響&#xff1f; 答案是肯定的&#xff01;服務器不備案&#xff0c;影響可不小。據相關數據顯示&a…

【LeetCode Solutions】LeetCode 176 ~ 180 題解

CONTENTS LeetCode 176. 第二高的薪水&#xff08;SQL 中等&#xff09;LeetCode 177. 第 N 高的薪水&#xff08;SQL 中等&#xff09;LeetCode 178. 分數排名&#xff08;SQL 中等&#xff09;LeetCode 179. 最大數&#xff08;中等&#xff09;LeetCode 180. 連續出現的數字…

D720201 PCIE 轉USB HUB

1. 啟動時出現了下面錯誤 [ 4.682595] pcieport 0004:00:00.0: Signaling PME through PCIe PME interrupt [ 4.684939] pci 0004:01:00.0: Signaling PME through PCIe PME interrupt [ 4.691287] pci 0004:01:00.0: enabling device (0000 -> 0002) [ 5.2962…

【愚公系列】《Manus極簡入門》028-創業規劃顧問:“創業導航儀”

&#x1f31f;【技術大咖愚公搬代碼&#xff1a;全棧專家的成長之路&#xff0c;你關注的寶藏博主在這里&#xff01;】&#x1f31f; &#x1f4e3;開發者圈持續輸出高質量干貨的"愚公精神"踐行者——全網百萬開發者都在追更的頂級技術博主&#xff01; &#x1f…

IBM BAW(原BPM升級版)使用教程第六講

續前篇&#xff01; 一、事件&#xff1a;Undercover Agent 在 IBM Business Automation Workflow (BAW) 中&#xff0c;Undercover Agent (UCA) 是一個非常獨特和強大的概念&#xff0c;旨在實現跨流程或系統的事件處理和觸發機制。Undercover Agent 主要用于 事件驅動的流程…

【強化學習】動態規劃(Dynamic Programming, DP)算法

1、動態規劃算法解題 LeetCode 931. 下降路徑最小和 給你一個 n x n 的 方形 整數數組 matrix &#xff0c;請你找出并返回通過 matrix 的下降路徑 的 最小和 。 下降路徑 可以從第一行中的任何元素開始&#xff0c;并從每一行中選擇一個元素。在下一行選擇的元素和當前行所選…

深入探索DSPy:開啟模塊化AI編程的新篇章

在當今快速發展的AI時代&#xff0c;語言模型&#xff08;LM&#xff09;的應用已經滲透到各個領域&#xff0c;從簡單的文本生成到復雜的多模態任務&#xff0c;語言模型展現出了強大的能力。然而&#xff0c;隨著應用場景的日益復雜&#xff0c;開發者們面臨著一個共同的挑戰…

List<T>中每次取固定長度的數據

工具類方法 package org.common.util; import java.util.ArrayList; import java.util.Iterator; import java.util.List;/*** 批處理取值組件* param <T>*/ public class BatchIterator<T> implements Iterator<List<T>> {private final List<T&g…