您的位置:首页 > 其它

线程和指针

2016-02-10 22:40 183 查看
//1.thread

#pragma mark - 线程间共享指针

/*

两个向量指针,sum字段(持有点积),length字段(定点积函数要用的向量的长度)

length字段表示线程处理的向量的部分,不是整个向量的长度

*/

pthread_mutex_t mutexSum;//全局区域声明它以充许多个线程访问

typedef struct {

double *vectorA;

double *vectorB;

double sum;

int length;

}VectorInfo;

/*

VectorInfo指针和计算点积向量的起始索引

*/

typedef struct {

VectorInfo *info;

int beginningIndex;

}Product;

/*

所有线程会在同一时间对两个向量进行计算,但是它们访问的是向量的不同部分,所以不会有冲突。

每个线程会计算自己负责的那些向量的各,不过,这个各需要累加到VectorInfo结构体的sum字段上。

多个线程可能会同时访问sum字段,所以需要用互斥锁保护数据,下面会声明互斥锁。同一时间互斥锁只允许

一个线程访问受保护的变量,声明互斥锁保护sum变量,在全局区域声明它以充许多个线程访问

*/

void dotProduct(void *prod){

Product *product = (Product *)prod;

VectorInfo *vectorInfo = product->info;

int beginningIndex = product->beginningIndex;

int endingIndex = beginningIndex +vectorInfo->length;

double total =
0;

for (int i = beginningIndex; i<endingIndex;i++) {

total +=(vectorInfo->vectorA[i] *vectorInfo->vectorB[i]);

}

pthread_mutex_lock(&mutexSum);

vectorInfo->sum += total;

pthread_mutex_unlock(&mutexSum);

pthread_exit((void *)0);

}

#define NUM_THREADS 4

void threadExample(){

VectorInfo vectorInfo;

double vectorA[]={1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0,11.0,12.0,13.0,14.0,15.0,16.0

};

double vectorB[]={1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0,11.0,12.0,13.0,14.0,15.0,16.0

};

vectorInfo.vectorA = vectorA;

vectorInfo.vectorB = vectorB;

vectorInfo.length =
4;

//创建4个元素的线程数组,初始化互斥锁和线程的属性字段

pthread_t threads[NUM_THREADS];

void *status;

pthread_attr_t attr;

pthread_mutex_init(&mutexSum,NULL);

pthread_attr_init(&attr);

pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_JOINABLE);

int returnValue;

int threadNumber;

//每次迭代都会创创建一个新的Product实例,会把vectorInfo的地址和一个基于threadNumber得到的唯一索引赋给它。

//然后创建线程

for (threadNumber =
0; threadNumber <NUM_THREADS; threadNumber ++) {

Product *product = (Product *)malloc(sizeof(Product));

product->beginningIndex = threadNumber *4;

product->info = &vectorInfo;

returnValue = pthread_create(&threads[threadNumber], &attr, (void *)dotProduct,(void *)product);

if (returnValue) {

printf("ERROR,Unable to create thread:%d\n",returnValue);

exit(-1);

}

}

//loop结束,销毁线程属性和互斥锁,for循环确保程序等到4个线程都完成后打印点积

pthread_attr_destroy(&attr);

for (int i =0; i<NUM_THREADS; i++) {

pthread_join(threads[i], &status);

}

pthread_mutex_destroy(&mutexSum);

printf("Dot Product sum:%lf\n",vectorInfo.sum);

pthread_exit(NULL);

}

//factorial

#pragma mark - 用函数指针支持回调

/*

1.回调定义:如果一个线程的事件导致另一个线程的函数调用。将回调函数的指针传递给线程,

而函数的某个事件会引发对回调函数的调用,这种方法在GUI应用程序中处理用户线程事件很有用。

2.factorial:阶乘,结果和回调函数指针。用这些数据计算阶乘,把结果保存到result字段,

调用回调函数,然后结束线程

*/

typedef struct _factorialData{

int number;

int result;

void (*callBack)(struct_factorialData *);

}FactorialData;

void factorial(void *agrs){

FactorialData *factorialData = (FactorialData*)agrs;

void(*callBack)(FactorialData*);

int number = factorialData->number;

callBack = factorialData->callBack;

int num = 1;

for (int i =1; i<=number; i++) {

num *= i;

}

factorialData->result = num;

callBack(factorialData);

pthread_exit(NULL);

}

void startThread(FactorialData *data){

pthread_t thread_id;

int thread = pthread_create(&thread_id,NULL,(void *(*)(void *))factorial,
(void *)data);

if (thread) {

printf("ERROR,Unable to create thread:%d\n",thread);

exit(-1);

}

}

void callBackFunction(FactorialData *factorialData){

printf("Factorial is %d \n",factorialData->result);

}

void initThread(){

FactorialData *datas = (FactorialData *)malloc(sizeof(FactorialData));

if (!datas) {

printf("Faild to allocate memory\n");

return ;

}

datas->number =
8;

datas->callBack =callBackFunction;

startThread(datas);

sleep(2000);//为所有线程正常结束提供足够的时间

}

//2.pointer alias

/*

指针的别名,如果两个指针引用同一内存地址,我们称一个指针是另一个指针的别名。别名并不罕见,不过可能会引发一些问题

强别名:它不允许一种类型的指针成为另一种类型的指针的别名

C是类型语言,在声明变量时就得为其指定类型,可以存在不同类型的多个变量

有时可能需要把一种类型转换成另一种类型,这一般是通过类型转换实现的,不过也可能使用联合体,类型双关就是指这种绕开

类型系统的技术

如果转换涉及指针,可能会产生严重的问题。为了说明这种技术,函数会判断一个浮点数是否为正,

这个可以正确工作,也不会涉及别名,因为没有用到指针

*/

typedef union _conversion{

float fNum;

unsigned int uiNum;

}Conversion;

int isPositivel(float number){

Conversion conversion ={.fNum = number};

return (conversion.uiNum & 0x80000000)==0;

}

float number = 3.25f;

unsigned int *ptrValue = (unsigned int *)&number;

unsigned int result = (*ptrValue & 0x80000000) == 0;

NSLog(@"result = %d",result);

/*3.

restric关键字可以在声明指针时告诉编译器这个指针没有别名,这样就允许编译器产生更高效的代码。

很多情况下这是通过缓存指针实现的,不过,编译器也可以选择不优化代码,如果用了别名,那么执代码会导致

未定义行为,编译器不会因为破坏强别名假设而提供任何警告信息

volatile关键字可以阻止运行时系统使用寄存器暂存端口值,每次访问端口都需要系统读写端口,而不是从寄存器中读

取一个可能已经过期的值。

如把所有变量声明为volatile,会阻碍编译器进行所有类型的优化

*/

void add(int size,double *restrict arr1,const double *restrict arr2){

for (int i =0; i<size ; i++) {

arr1[i] += arr2[i];

}

}

/*4.判断机器的字节序,如在Intel PC上输出,这是小字节序架构,内存中分配:

//100:78

//101:56

//102:34

//103:12

*/

int num = 0x12345678;

char *pc = (char *)#

for (int i =0; i<4; i++) {

NSLog(@"%p:%02x",pc,(unsignedchar)*pc++);

}

int main(int argc,constchar * argv[]) {

threadExample();

initThread();

double vector1[] = {1.1,2.2,3.3,4.4};

double vector2[] = {1.1,2.2,3.3,4.4};

double *vector3 = vector2;

add(4,vector1,vector2);

NSLog(@"%d",isPositivel(-3.2));

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: