我太鹹魚了,一個月前制定的計劃,現在還沒完成。我決定把要寫的先寫在這裏,免得我忘記了。
- 無鎖循環隊列kfifo
- CPU親和性設定
- 設置大小端判定宏
- 安裝OCCI,zlib,libpcap(centos7)
1 實現無鎖環形隊列kfifo。(雖然我知道他只能實現單消費者單生產者,但是 看看 DPDK ring的實現或許可以 整一個好一點的)
2 CPU親和性設定
linuxC語言裏有 將線程綁定到特定CPU核的方法。通過這個方法或許可以避免上下文切換(關鍵是 問題可以被 多線程處理切分而不出現問題,就好像矩陣乘法那樣)
linux中的線程:linux裏是沒有線程的。所有的線程都是 用LWP(輕量級進程)來模擬的。linux裏有一個進程號,兩個線程號。分別是
進程pid: getpid()
POSIX線程tid: pthread_self() //進程內唯一,但是在不同進程則不唯一。因爲是POSIX標準的線程號(我的理解是 封裝了操作系統的API使之統一)。
線程pid: syscall(__NR_gettid) //系統內是唯一的
或者 syscall(SYS_gettid)
對於單線程的進程,內核中tid==pid,對於多線程進程,他們有相同的pid,不同的tid。tid用於描述內核真實的pid和tid信息(轉)
pthread_self返回的是posix定義的線程ID,man手冊明確說明了和內核線程tid不同。它只是用來區分某個進程中不同的線程,當一個線程退出後,新創建的線程可以複用原來的id。 而 這三個 線程pid是可以保證操作系統都不一樣的。
gettid 獲取的是內核中真實線程ID, 對於多線程進程來說,每個tid實際是不一樣的。
而pthread_self獲取的是相對於進程的線程控制塊的首地址, 只是用來描述統一進程中的不同線程,
例子中,在線程中調用fork,只會將當前活動線程設置爲活動(其他線程終止),且進程使用的都是虛擬地址,所以產生的pthread_self() 是相同的。(轉)
上述不匹配,對程序的實際運行,並沒有影響,因爲他們的tid是不同的
關於這三個的介紹,參見這個博客
https://blog.csdn.net/rsyp2008/article/details/45150621
POSIX標準介紹如下:https://www.cnblogs.com/1130136248wlxk/articles/5308863.html
具體代碼如下:
#define _GNU_SOURCE
#include <sched.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <iostream>
#include <pthread.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <sys/syscall.h> // 你要注意 整 這個 __NR_gettid 需要這個頭文件。
using namespace std;
/* sysconf( _SC_NPROCESSORS_CONF ) 查看cpu的個數;打印用%ld長整。
* sysconf( _SC_NPROCESSORS_ONLN ) 查看在使用的cpu個數;打印用%ld長整 */
void *cosumer(void *args){
int *m=(int*)args;
cpu_set_t mask;
cout<<*m<<endl;
CPU_ZERO(&mask); /* 初始化set集,將set置爲空*/
CPU_SET(*m, &mask);
pthread_setaffinity_np(pthread_self(),sizeof(mask), &mask);
// 將當前 線程綁定到 mask裏的core編號裏,你要知道我每次都用的不同的m。
long long mm=pthread_self();
if(*m==0)
cout<<"*"<<*m<<"???"<<"*"<<getpid()<<"*"<<getgid()<<"*"<<mm<<"*"<<"*"<<syscall(__NR_gettid)<<endl;
else
cout<<"*"<<*m<<"?????"<<"*"<<getpid()<<"*"<<getgid()<<"*"<<mm<<"*"<<"*"<<syscall(__NR_gettid)<<endl;
// 依次是pid ,getgid是進程組號()。
/// syscall是 系統線程號。
cpu_set_t get;// 查詢 綁定情況。
CPU_ZERO(&get);
int tt=0;
pthread_getaffinity_np(pthread_self(), sizeof(get), &get) ;// 綁定core
//printf("get CPU affinity failue, ERROR:%s\n", strerror(errno));
/*查看運行在當前進程的cpu*/
for(int i = 0; i < 2; i++) {
if (CPU_ISSET(i, &get)) { /*查看cpu i 是否在get 集合當中*/
printf("this process %d of running processor: %d %lld %d\n", getpid(), i,pthread_self(),syscall(__NR_gettid));
}
}
return NULL;
}
int main(int argc, char **argv)
{ cout<<"???"<<" "<<getpid()<<" "<<getgid()<<" "<<endl;
int cpus = 0;
int i = 0;
cpu_set_t mask;
cpu_set_t get;
cpus = sysconf(_SC_NPROCESSORS_CONF);
printf("cpus: %d\n", cpus);
CPU_ZERO(&mask); /* 初始化set集,將set置爲空*/
CPU_SET(0, &mask); /* 依次將0、1、2、3號cpu加入到集合,前提是你的機器是多核處理器*/
CPU_SET(1, &mask);
//CPU_SET(2, &mask);
//CPU_SET(3, &mask);
/*設置cpu 親和性(affinity)*/
pthread_t x[2];
//cout<<"wwww"<<endl;
int a[2]={0,1};
for(int i=0;i<2;i++){
int ret=pthread_create(&x[i],NULL,cosumer,(void *)(&a[i]));
//pthread_join(x[i],0);
//cout<<pthread_self()
if(ret==1){puts("w");continue;}
//pthread_setaffinity_np(x[i],sizeof(mask), &mask);
}
/*if (sched_setaffinity(0, sizeof(mask), &mask) == -1) {
printf("Set CPU affinity failue, ERROR:%s\n", strerror(errno));
return -1;
}
*/
usleep(1000); /* 讓當前的設置有足夠時間生效*/
/*查看當前進程的cpu 親和性*/
CPU_ZERO(&get);
//cout<<"2222222"<<endl;
int tt=0;
pthread_getaffinity_np(x[tt], sizeof(get), &get) ;
//printf("get CPU affinity failue, ERROR:%s\n", strerror(errno));
//return -1;
/*查看運行在當前進程的cpu*/
for(i = 0; i < cpus; i++) {
if (CPU_ISSET(i, &get)) { /*查看cpu i 是否在get 集合當中*/
printf("this process %d of running processor: %d %lld\n", getpid(), i,pthread_self());
}
}
sleep(3); //讓程序停在這兒,方便top命令查看
return 0;
}
註釋:這兩個線程的輸出成功的亂序了。
2843 是 主線程號。1000是主線程 組號
cpu核心數爲2(我的虛擬機我就分了2)
第一個線程的 tid 爲2843, posix線程id爲139976734291712 內核線程id爲2844
第二個線程 的tid爲2843 poix爲139976725899008 內核線程id爲2845。
並且 通過查詢發現 綁定成功。okey
3大小端宏的設定:
我假定libpcap已經解決大小端宏的問題了(網絡傳輸是大端,而如果電腦是小端,那麼如何處理包)
②那個關鍵的宏定義 WORDS_BIGENDIAN 在libpcap裏是否有
我的傾向是沒有,因爲如果有,那麼我上一次的代碼,裏面的ip報頭中有關於就應該正確的運行,代碼部分:
#ifdef WORDS_BIGENDIAN
u_int8_t ip_version:4.
ip_header_length:4;
#else
u_int8_t ip_header_length:4.
ip_version:4;
#endif
不能運行,所以我懷疑這個 關鍵字得自己定義。(此處存疑。這部分代碼來源於 網絡安全開發包詳解)
於是手工判斷大小端,參照linux源碼
大端:低位在前。比如0x12345678
存儲爲 0x78 0x56 0x34 0x12
小端爲 0x12 0x34 0x56 0x78
#include <iostream>
#include <bits/stdc++.h>
#define kkk 10
#define ENDIANNESS ((char)endian_test.l)
using namespace std;
static union {
char c[4];
unsigned long l;
} endian_test= { { 'l', '?', '?', 'b' } };
int main()
{ if('b'==ENDIANNESS){
#define big
}// 如果定義了這個宏,就是大端。之所以這麼寫
#ifdef big
printf("大端啊哥哥");
#else
printf("dd");
#endif
return 0;
}
https://www.cnblogs.com/wawahaha/p/3821486.html (libpcap)
https://blog.csdn.net/sirria1/article/details/83115582(zlib)
https://blog.csdn.net/freeking101/article/details/55506897(oralcle連接代碼)
https://blog.csdn.net/wjb123sw99/article/details/83863234(occi)