Linux 下C語言多線程編程

進程與線程的區別

進程擁有獨立的地址空間,而且進程間的數據空間也相互獨立,數據的傳遞得通過通信的方式;

線程是在一個進程下同時運行,多個線程之間的數據共享

線程的啓動

函數原型:

/* Create a new thread, starting with execution of START-ROUTINE
   getting passed ARG.  Creation attributed come from ATTR.  The new
   handle is stored in *NEWTHREAD.  */
extern int pthread_create (pthread_t *__restrict __newthread,
			   const pthread_attr_t *__restrict __attr,
			   void *(*__start_routine) (void *),
			   void *__restrict __arg) __THROWNL __nonnull ((1, 3));

第一個參數爲指向線程標識符的指針;
第二個參數爲線程的屬性;
第三個參數是線程運行函數的起始地址;
第四個參數是運行函數的參數;
z注:返回0表示創建成功,非o創建失敗;EAGAIN表示系統不允許創建(線程數量過多),EINVAL 第二個參數的屬性非法

線程的退出

1 線程函數執行完返回

2 調用pthread_exit結束

相關函數

pthread_join函數

/* Make calling thread wait for termination of the thread TH.  The
   exit status of the thread is stored in *THREAD_RETURN, if THREAD_RETURN
   is not NULL.

   This function is a cancellation point and therefore not marked with
   __THROW.  */
extern int pthread_join (pthread_t __th, void **__thread_return);

第一個參數爲等待的線程的標識符

第二個參數爲用戶定義的指針,它可以用來存儲被等待線程的返回值

:這個函數是一個線程阻塞函數,調用它將會一直等着被等帶的線程函數執行完返回

pthread_detach函數

/* Indicate that the thread TH is never to be joined with PTHREAD_JOIN.
   The resources of TH will therefore be freed immediately when it
   terminates, instead of waiting for another thread to perform PTHREAD_JOIN
   on it.  */
extern int pthread_detach (pthread_t __th) __THROW;

參數就是線程的標識符,一旦調用該函數,該線程就不能再調用pthread_join加入等待列表,線程函數執行完以後會立即釋放資源,使用此函數時一般不關心執行結果。

pthread_exit函數

/* Terminate calling thread.

   The registered cleanup handlers are called via exception handling
   so we cannot mark this function with __THROW.*/
extern void pthread_exit (void *__retval) __attribute__ ((__noreturn__));

參數是函數的返回值,只要pthread_join的第二個參數不是NULL,這個值將被傳遞給__thread_return

:一個線程不能被多個線程等待,否則第一個接收到信號的線程成功返回,其餘調用pthread_join的線程返回錯誤,錯誤代碼:ESRCH

Demo 代碼

#include <pthread.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#include "keyboard.h"

#define MAX_THREAD_COUNT 10

typedef struct thread_s {
    pthread_t thread;                //線程標誌符
    void *(*start_routine)(void *);  //函數指針,需要執行的函數
    void *arg;                       //指針函數的參數
    int blocked;                     //線程運行狀態標誌
    int started;                     //現場啓動標誌
} thread_t;

static thread_t threads[MAX_THREAD_COUNT];  //定義一個靜態數組存放線程信息
static int thread_cnt = 0;                  //已有線程的數據

static int quit = 0;  //標記是否退出線程

static void add_thread(void *(*start_routine)(void *), void *arg, int blocked) {
    if (thread_cnt >= MAX_THREAD_COUNT)
        return;
    threads[thread_cnt].start_routine = start_routine;
    threads[thread_cnt].arg = arg;
    threads[thread_cnt].blocked = blocked;
    threads[thread_cnt].started = 0;
    thread_cnt++;
}

static void start_thread(void) {
    int i;
    for (i = 0; i < thread_cnt; i++) {
        //創建一個線程
        if (pthread_create(&threads[i].thread, NULL, threads[i].start_routine,
                           threads[i].arg) == 0) {
            threads[i].started = 1;
        } else {
            fprintf(stderr, "%s(): cannot create thread %d\n", __FUNCTION__, i);
        }
    }
}

static void exit_thread(void) {
    int i;
    for (i = 0; i < thread_cnt; i++) {
        if (threads[i].started) {
            if (threads[i].blocked)
                pthread_kill(threads[i].thread, SIGHUP);
            pthread_join(threads[i].thread, NULL);
        }
    }
}

static void *test_thread_a(void *arg) {
    while (!quit) {
        //在這裏添加需要執行的代碼
        fprintf(stderr, "%s(): thread is running!\n", __FUNCTION__);
        sleep(2);
    }

    fprintf(stderr, "%s(): thread terminated!\n", __FUNCTION__);
}

static void *test_thread_b(void *arg) {
    while (1) {
        fprintf(stderr, "%s(): thread is running!\n", __FUNCTION__);
        sleep(3);
    }
    fprintf(stderr, "%s(): thread terminated!\n", __FUNCTION__);
}

int main(int argc, char **argv) {
    int _char;
    add_thread(test_thread_a, NULL, 0);
    add_thread(test_thread_b, NULL, 1);

    start_thread();

    //初始化鍵盤輸入
    if (init_keyboard() != 0) {
        fprintf(stderr, "init_keyboard failed\n");
    } else {
        fprintf(stderr, "Press Q or q quit\n");
    }

    while (!quit) {
        //接收所有鍵盤輸入的字符,如果有Q或者q就退出程序
        while ((_char = __getch()) >= 0) {
            if (_char == 'Q' || _char == 'q') {
                quit = 1;
                break;
            }
        }
        sleep(2);
    }

    close_keyboard();
    exit_thread();
    return 0;
}

完整代碼

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章