CC++ 多线程及加锁解锁

时间:2024-03-24 08:59:16

1、为什么用多线程?
并行处理任务,更快获得计算结果。

线程编程步骤:
1 线程id申明:pthread_t pid1;
2 线程创建函数:int ret=pthread_cread(&pid1, NULL, *Fuc, (void *)Fuc_args);
线程创建成功返回值为0,失败返回错误代码。
第一个参数是线程id地址;第二个参数是线程属性,值为NULL时表示使用线程默认属性;
第三个参数是线程函数入口地址(经测试该函数不用非得是空指针函数void * TestIp(void *args)????;
第四个参数是线程入口函数参数地址,1个参数传该参数的地址即可,多个参数用结构体地址来传递;
3 线程回收函数:pthread_join(pthread_t pid, NULL); 以阻塞的方式等待pid线程结束,并回收线程资源。
4 定义线程函数:(类型)Fuc { }

2、为什么加锁?
多线程访问共享资源时,为防止产生脏数据和错误而采取的方式。多线程访问同一个数据库时,数据库是共享资源,所以对库操作要加锁。
举例:1个厕所不能提供多人用,进入厕所加锁,使用完解锁,一个道理。

线程加锁步骤:
1 公共头文件a.h引用线程头文件 #include <pthread.h>
2 声明互斥锁的全局变量
extern phread_mutex_t sql_mutex;
3 宏定义加锁解锁操作
#define SQL_LOCK do{phread_mutex_lock(&sql_mutex);}while(0)
#define SQL_UNLOCK do{phread_mutex_unlock(&sql_mutex);}while(0)
4 代码引用头文件进行访问共享资源代码前一步加解锁操作,加锁太前了影响性能。
#include <a.h>

	SQL_LOCK;
	<操作共享数据>
	SQL_UNLOCK;

3、线程编程及线程加解锁栗子:获取局域网内可用的IP并排序显示,15s左右出结果

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <pthread.h>
#include <time.h>

int useful_ip_count = 0;
char *useful_ip[252] = {0};
char ip_net[128] = {0};

pthread_mutex_t data_mutex = PTHREAD_MUTEX_INITIALIZER;
#define  DATA_LOCK		do{pthread_mutex_lock(&data_mutex);} while (0)
#define  DATA_UNLOCK	do{pthread_mutex_unlock(&data_mutex);} while (0)

void get_ip_net();
//void * TestIp(void *args); 一直以为线程函数是这种空指针函数,其实任何函数都可以,该例子用了整型函数一样可以获取正确结果
int TestIp(void *args);
void sort_ip_asc();

int main(int argc, char **argv) {

	time_t ts,tf;
	ts=time(NULL);

	int ret=0;
	int i;
	char test_ip[64] = {0};
	pthread_t pid[255];

	get_ip_net();

	if (strlen(ip_net)<6)
		exit(-1);

	for (i=2;i<255;i++)
	{	
		memset(test_ip, 0, 64);
		sprintf(test_ip,"%s%d",ip_net,i);
		//if ((ret=pthread_create(&pid[i], NULL, (void *)TestIp, (void *)strdup(test_ip))) !=0)
		if ((ret=pthread_create(&pid[i], NULL, (void *)&TestIp, (void *)strdup(test_ip))) !=0)
		{
			printf("create pthread failed, pid NO. is %d;error NO. is %d.\n", i, ret);
		}
	}

	for (i=2;i<255;i++)
	{	
		pthread_join(pid[i], NULL);
	}

	printf("This local net has %d useful ip:\n",useful_ip_count);
	sort_ip_asc();
	for (i=0;i< useful_ip_count;i++)
	{
		printf(" %d: %s\n", i, useful_ip[i]);
	}

	for (i=0;i< useful_ip_count;i++)
	{
		if(useful_ip[i] != NULL) 
			free(useful_ip[i]);
	}

	tf=time(NULL);
	printf("Time cost:%d second\n",(int)(tf-ts));
	return 0;
}

void get_ip_net(){

	char tmp[256] = {0};
	char *p		  = NULL;
	
	strcpy(tmp,"route -n |grep UG |awk '{print $8}'|xargs ifconfig |grep \"inet addr:\" |awk '{print $2}' |awk -F: '{print $2}' >/root/ip.dat");

	if(strlen(tmp)>0 && !system(tmp)) {
		FILE *Fp = fopen("/root/ip.dat","r");
		if (Fp != NULL)
		{
			fgets(ip_net, 127, Fp);
			fclose(Fp);

			p=strrchr(ip_net, '.');
			if (p != NULL)
				*(p+1)='\0';
		}
	}
}

//void *TestIp(void *args) {
//	char tmp[128] = {0};
//	char *ip	  = NULL;
//
//	ip = (char *)args;	
//	sprintf(tmp,"ping -c 2 %s >/dev/null 2>&1", ip);
//	if (!system(tmp))
//	{
//		DATA_LOCK;
//		useful_ip[useful_ip_count] = strdup(ip);
//		useful_ip_count++;		
//		DATA_UNLOCK;
//	}
//
//	if(ip != NULL) 
//		free(ip);
//
//	return NULL;
//}

int TestIp(void *args) {
	char tmp[128] = {0};
	char *ip	  = NULL;

	ip = (char *)args;	
	sprintf(tmp,"ping -c 2 %s >/dev/null 2>&1", ip);
	if (!system(tmp))
	{
		DATA_LOCK;
		useful_ip[useful_ip_count] = strdup(ip);
		useful_ip_count++;		
		DATA_UNLOCK;
	}

	if(ip != NULL) 
		free(ip);

	return 0;
}

void sort_ip_asc(){

	int i, j, lastSwap;
	int p1,p2;
	char *tmp = NULL;
	char *p	  = NULL;

	for (j=useful_ip_count-1; j>0; j=lastSwap) {
		lastSwap=0;     //每一轮要初始化为0,防止某一轮未发生交换,lastSwap保留上一轮的值进入死循环
		for (i=0; i<j; i++) {//get a max number one for loop
			if (useful_ip[i] == NULL || useful_ip[i+1] == NULL)
				break;

			p=strrchr(useful_ip[i], '.');
			p1=atoi(p+1);

			p=strrchr(useful_ip[i+1], '.');
			p2=atoi(p+1);

			if (p1 > p2) {
				tmp				= useful_ip[i];
				useful_ip[i]	= useful_ip[i+1];
				useful_ip[i+1]  =tmp;
				//最后一次交换位置的坐标
				lastSwap = i;
			}
		}
	}
}

编译:gcc -g a.c -lpthread -o a -Wall
执行结果:C\C++ 多线程及加锁解锁

[root~]# ./a
This local net has 22 useful ip:
0: 192.168.1.12
1: 192.168.1.50
2: 192.168.1.99
3: 192.168.1.100
4: 192.168.1.104
5: 192.168.1.112
6: 192.168.1.113
7: 192.168.1.114
8: 192.168.1.117
9: 192.168.1.128
10: 192.168.1.132
11: 192.168.1.150
12: 192.168.1.155
13: 192.168.1.156
14: 192.168.1.188
15: 192.168.1.191
16: 192.168.1.192
17: 192.168.1.198
18: 192.168.1.203
19: 192.168.1.216
20: 192.168.1.250
21: 192.168.1.254
Time cost:11 second