1. 程式人生 > >C語言實現一種建立易管理易維護執行緒的方法

C語言實現一種建立易管理易維護執行緒的方法

一、什麼是執行緒?

在一個程式中的多個執行路線就叫做執行緒。
就個人理解而言,一個執行緒就是一個程序裡的一個while(1),一般情況下執行緒是不會退出的。
而多執行緒自然就是一個程序裡的多個while(1)了。
《西遊記》中,有一種有趣的設定——“天上一天,地上一年”。
而在現實世界中,隨著技術發展,CPU的效能越來越高,誇張點說:“CPU一年,地上一天”。
為了高效利用CPU效能,多程序的方式豐富了作業系統,無論是windows還是Linux系統,程式都是“輪班”跑的,放慢些看,就是這個執行一會兒,然後讓出CPU,其他程式再執行一會兒,然而我們看起來就是同時執行的。
多執行緒也是這樣的。

二、linux下執行緒函式

Linux系統下的多執行緒遵循POSIX執行緒介面,稱為pthread。編寫Linux下的多執行緒程式,需要使用標頭檔案pthread.h,在編譯時注意加上-lpthread引數,以呼叫靜態連結庫;pthread並非Linux系統的預設庫

1、pthread_create

  • pthread_create是UNIX環境建立執行緒函式
  • int pthread_create(pthread_t *restrict tidp,const pthread_attr_t *restrict_attr,void*(*start_rtn)(void*),void *restrict arg);
  • 若成功則返回0,否則返回錯誤碼
  • 第一個引數為指向執行緒識別符號的指標;二個引數用來設定執行緒屬性;第三個引數是執行緒執行函式的地址;最後一個引數是執行函式的引數

2、pthread_join

  • 函式pthread_join用來等待一個執行緒的結束
  • extern int pthread_join __P (pthread_t __th, void **__thread_return);
  • 如果執行成功,將返回0,失敗則返回錯誤碼
  • 第一個引數為被等待的執行緒識別符號;第二個引數為一個使用者定義的指標,它可以用來儲存被等待執行緒的返回值。
  • 這個函式是一個執行緒阻塞的函式,呼叫它的函式將一直等待到被等待的執行緒結束為止,當函式返回時,被等待執行緒的資源被收回
#include <stdio.h>
#include <pthread.h> 
void *threadfun(void *arg)
{
    printf("hello \n");
} 
 int main(void)
{
  pthread_t id;
  int i,ret;
  ret=pthread_create(&id,NULL,threadfun,NULL); 
  if(ret!=0) {
    printf ("Create pthread error!\n");
    exit (1);
  }
  pthread_join(id,NULL);
  return (0);
} 

補充:
printf("current thread id:%u\n", (unsigned int)pthread_self());可打印出當前執行緒id。

三、建立易管理易維護的執行緒

檔案均為為給力同事所傳。為防丟失忘記,因此記錄於此。

1、優勢:

  • 可設定優先順序
  • 易檢視

2、使用

在工程中加入下面的c檔案和h檔案。
包標頭檔案,然後這樣建立:

    static int port = 14000;
    printf("current thread id:%u\n", (unsigned int)pthread_self());
    ThreadCreateParaDef tThreadCreatePara;
    memset(&tThreadCreatePara, 0, sizeof(ThreadCreateParaDef));
    tThreadCreatePara.ps8Name = (char *)"receiveJobs";
    tThreadCreatePara.pvFuncPara = &port;
    tThreadCreatePara.EntryFuncPt = gSoapServerThread;
    createThread(&tThreadCreatePara);

3、檢視步驟

ps -ef | grep fw_ro* 檢視程序id

top -H -p 16002檢視程序的執行緒,效果如下圖:
PID為29527的執行緒即為receiveJobs執行緒。
這裡寫圖片描述

4、附錄

cbasethread.h

#ifndef CBAETHREAD_H
#define CBAETHREAD_H

typedef struct ThreadCreateParaDef
{
    char *ps8Name;                                              // 執行緒名稱
    void *(*EntryFuncPt)(void *);                               // 執行緒入口函式
    void *pvFuncPara;                                           // 執行緒引數
    int s32OldCancelState;
    int s32OldCancelType;
}ThreadCreateParaDef;

int CreateThread(ThreadCreateParaDef *ptThreadCreatePara);

#endif // MSG_DISTRIBUTION_H

cbasethread.c

#include <pthread.h>
#include <unistd.h>
#include <stdlib.h>
#include <memory.h>
#include <sys/prctl.h>
#include "cbasethread.h"


void *ThreadInterface(void *pvPara)
{
    ThreadCreateParaDef *ptThreadCreatePara = (ThreadCreateParaDef *)pvPara;
    void *pvFuncPara = ptThreadCreatePara->pvFuncPara;
    /*
    設定本執行緒對Cancel訊號的反應,state有兩種值:PTHREAD_CANCEL_ENABLE(預設)
    和PTHREAD_CANCEL_DISABLE,分別表示收到訊號後設為CANCLED狀態和忽略CANCEL信
    號繼續執行;old_state如果不為NULL則存入原來的Cancel狀態以便恢復。
    */
    pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &ptThreadCreatePara->s32OldCancelState);
    /*
    設定本執行緒取消動作的執行時機,type有兩種取值:PTHREAD_CANCEL_DEFERRED和
    PTHREAD_CANCEL_ASYNCHRONOUS,僅當Cancel狀態為Enable時有效,分別表示收到
    訊號後繼續執行至下一個取消點再退出和立即執行取消動作(退出);oldtype如
    果不為NULL則存入運來的取消動作型別值。
    */
    pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &ptThreadCreatePara->s32OldCancelType);

    prctl(PR_SET_NAME, ptThreadCreatePara->ps8Name);

    if(NULL != pvPara)
    {
        free(pvPara);
    }

    (*ptThreadCreatePara->EntryFuncPt)(pvFuncPara);

    return NULL;
}

pthread_t TaskSpawn
(
    char *ps8Name,                                          /* 任務的名稱 */
    int s32Priority,                                        /* 實時任務的優先順序 1-99 */
    void *(*pvEntryPt)(void *),                             /* 任務的函式入口 */
    void *pvFuncPara,                                       /* 這是一個指標值,任務入口函式的入參 */
    int s32Schedule                                         /*指定fifo 、rr或者normal排程方法*/
)
{
    int ret = 0;
    struct sched_param tSchParam;
    pthread_attr_t tThreadAttr;
    pthread_t tThreadID;
    int s32SchPolicy;

    if(NULL == pvEntryPt)
    {
        return 0;
    }

    /*判斷優先順序的正確性*/
    if (s32Priority > 99 || s32Priority < 0)
    {
        return 0;
    }

    /*初始化執行緒引數*/
    pthread_attr_init(&tThreadAttr);

    /*設定排程策略*/
    pthread_attr_getschedpolicy(&tThreadAttr, &s32SchPolicy);
    s32SchPolicy = s32Schedule;                                       /*建立的所有任務都將是實時任務*/
    pthread_attr_setschedpolicy(&tThreadAttr, s32SchPolicy);

    /*設定程序為分離狀態,任務分離後將不需要用pthread_join()等待執行緒退出*/
    pthread_attr_setdetachstate(&tThreadAttr, PTHREAD_CREATE_DETACHED);

    if (SCHED_FIFO == s32Schedule || SCHED_RR == s32Schedule)
    {
        /* 設定實時任務的優先順序*/
        pthread_attr_getschedparam(&tThreadAttr, &tSchParam);
        tSchParam.sched_priority = s32Priority;
        pthread_attr_setschedparam(&tThreadAttr, &tSchParam);
    }

    ret = pthread_create(&tThreadID, &tThreadAttr, pvEntryPt, pvFuncPara);
    if(0 != ret)
    {
        perror(NULL);
        printf("TaskSpawn-%s create error", ps8Name);
        return 0;
    }

    return tThreadID;
}

int CreateThread(ThreadCreateParaDef *ptThreadCreatePara)
{
    pthread_t tThreadSysID;
    ThreadCreateParaDef *pthreadPara = NULL;

    pthreadPara = (ThreadCreateParaDef *)malloc(sizeof(ThreadCreateParaDef));
    memcpy(pthreadPara, ptThreadCreatePara, sizeof(ThreadCreateParaDef));

    tThreadSysID = TaskSpawn(ptThreadCreatePara->ps8Name, 1, ThreadInterface, pthreadPara, SCHED_RR);
    if(!tThreadSysID)                                                    // 執行緒啟動有問題
    {
        printf("Thread startup error\n");
        if (pthreadPara != NULL)
        {
            free(pthreadPara);
        }
        return -1;
    }

    return 0;
}