竞争示例
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#define LEFT 30000000
#define RIGHT 30000200
#define THRNUM (RIGHT - LEFT + 1)
static void *the_primer (void *p); //这行必不可少,否则第17行会报错,因为无法检测到该函数
int main()
{
int i;
pthread_t tid[THRNUM];
int err;
for(i = LEFT; i <= RIGHT; i++){
err = pthread_create(tid + i - LEFT,NULL, the_primer, &i);
if(err){
fprintf(stderr, "pthread_create(): %sn", strerror(err));
exit(1);
}
}
//上面创建了200个进程来进行运算
for(i = LEFT; i <= RIGHT; i++)
pthread_join(tid[i - LEFT], NULL);
exit(0);
}
static void *the_primer(void *p){
int i,j,mark;
i = *(int *)p;
mark = 1;
for(j = 2; j < i/2; j++){
if(i % j == 0){
mark = 0;
break;
}
}
if(mark){
printf("%d is a primern", i);
}
pthread_exit(NULL);
}
输出:
解析: 可以看到,这个函数的目的是将30000000到30000200中的所有质数打印。但是出来的结果却是完全不同的,这是因为多个线程出现了竞争。200个进程有共享的数据,并且没有加以保护。200个指针都指向了同一个地址空间。
程序改进方法1
我们知道,这个程序错误的原因是我们用的是引用传递,也就是传入的是i的引用,所以有可能让多个线程同时指向i的地址。那么我们就不用引用传递,而采用值传递。 注意:这个方法不好,多次采用强制转换
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#define LEFT 30000000
#define RIGHT 30000200
#define THRNUM (RIGHT - LEFT + 1)
static void *the_primer (void *p);
int main()
{
int i;
pthread_t tid[THRNUM];
int err;
for(i = LEFT; i <= RIGHT; i++){
err = pthread_create(tid + i - LEFT,NULL, the_primer, i);
if(err){
fprintf(stderr, "pthread_create(): %sn", strerror(err));
exit(1);
}
}
for(i = LEFT; i <= RIGHT; i++)
pthread_join(tid[i - LEFT], NULL);
exit(0);
}
static void *the_primer(void *p){
int i,j,mark;
i = (int)p;
mark = 1;
for(j = 2; j < i/2; j++){
if(i % j == 0){
mark = 0;
break;
}
}
if(mark){
printf("%d is a primern", i);
}
pthread_exit(NULL);
}
输出:
方法2(结构体)
让201个i指向不同的空间,方法是定义一个结构体。值得注意的是,最后应该将malloc产生的指针释放掉,避免内存泄露
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#define LEFT 30000000
#define RIGHT 30000200
#define THRNUM (RIGHT - LEFT + 1)
static void *the_primer (void *p);
struct thr_args_st
{
int n;
};
int main()
{
int i;
pthread_t tid[THRNUM];
int err;
struct thr_args_st *p;
void *ptr; //作用是用来接收返回的指针,并且进行销毁。保证malloc和free在一个模块中
for(i = LEFT; i <= RIGHT; i++){
p = malloc(sizeof(*p));
if(p == NULL){
perror("malloc()");
exit(1);
}
p->n=i;
err = pthread_create(tid + i - LEFT,NULL, the_primer,p);
if(err){
fprintf(stderr, "pthread_create(): %sn", strerror(err));
exit(1);
}
}
for(i = LEFT; i <= RIGHT; i++)
{
pthread_join(tid[i - LEFT], ptr);
free(ptr);
}
exit(0);
}
static void *the_primer(void *p){
int i,j,mark;
i = ((struct thr_args_st *)p)->n;
free(p);
mark = 1;
for(j = 2; j < i/2; j++){
if(i % j == 0){
mark = 0;
break;
}
}
if(mark){
printf("%d is a primern", i);
}
pthread_exit(&p);
}
输出:
解析: 最终返回了一个指针并且在返回之后free,目的就是让malloc和free一一对应,能在同一个模块中。
注意:
因为这块涉及大量C++的知识,我还掌握不是很好,打算今天下午开始学习C++这方面的内容,给出更详细的解释。