C語言實現一種建立易管理易維護執行緒的方法
阿新 • • 發佈:2019-02-17
一、什麼是執行緒?
在一個程式中的多個執行路線就叫做執行緒。
就個人理解而言,一個執行緒就是一個程序裡的一個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;
}