1.1 基本概念为了确保同一时间只有一个线程访问数据,在访问共享资源前需要对互斥量上锁。一旦对互斥量上锁后,任何其他试图再次对互斥量上锁的线程都会被阻塞,即进入等待队列。 上面的文字用伪代码表示:
有些同学可能觉得通过代码很容易实现,其实不然。比方说下面这样:
上面这种做法是错误的,你有没有想过,标记 flag 也是共享资源? 实际上,有一种称之为 peterson 的算法可以解决两线程互斥问题,它的原理并不容易,如果你对此有兴趣,请参考《深入理解互斥锁的实现》。 1.2 互斥量的数据类型pthread 中,互斥量是用 pthread_mutex_t 数据类型表示的,通常它是一个结构体。在使用它前,必须先对它进行初始化。有两种方法可以对它进行初始化:
在上面的函数中,有两点需要提一下:
1.3 互斥量的加锁和解锁
在第 1.1 节中说,如果试图对一个已加锁的互斥量上锁,会让线程阻塞进入等待队列,实际上这是对 pthread_mutex_lock 函数说的。 如果使用 pthread_mutex_trylock,无论互斥量之前有没有上锁,线程会立即返回而不会阻塞,它是通过返回值来判断是否上锁成功:
所以这两种上锁的函数唯一区别就是一个是阻塞函数,另一个是非阻塞函数。不过通常不使用非阻塞版本的,它会浪费 cpu,除非你别有用意。 有同学可能会好奇,为什么我们自己用一个共享的 flag 变量做标记不行,而这里的 lock 函数却可以做到?这是因为 lock 函数对 mutex 的操作是原子的,所谓的原子操作,就是要么一次执行成功,要么一次执行失败。而你使用全局 flag 变量,是做不到这一点的,从 if (flag == 0) 到 flag = 1的赋值操作是分成了两个步骤,翻译成汇编语句那就需要更多条了。所以如果你想自己实现这样的原子操作,就只能使用汇编语句来编写啦,有可能的话,后面我自己用代码来实现一个!(当然用关中断也可以,只不过没必要如此麻烦。) 示例: #include<string.h> #include<stdio.h> #include<unistd.h> #include<pthread.h> pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; struct UpgradeParamSet { char value[1024]; int length; }; struct UpgradeParamSet parambak; //int gflag = 0; void* UpgradeParamSet_tcp(void* data) { struct UpgradeParamSet param; memset(¶m,0,sizeof(struct UpgradeParamSet)); memcpy(¶m, (void*)data, sizeof(struct UpgradeParamSet)); printf("UpgradeParamSet_tcp param.value=%s,param.length=%d\r\n",param.value,param.length); //sySendMsgToUpgradeClient(param.value,param.length); return NULL; } void UpgradeParamSet_thread(const char *value) { pthread_mutex_lock(&lock); int nRet = -1; pthread_t clientTid; //struct UpgradeParamSet param; memset(¶mbak,0, sizeof(struct UpgradeParamSet)); if(strlen(value)>1023){ strncpy(parambak.value,value,1023); }else{ strcpy(parambak.value,value); } parambak.length = strlen(parambak.value); printf("UpgradeParamSet_thread parambak.value=%s,parambak.length=%d\r\n",parambak.value,parambak.length); nRet = pthread_create(&clientTid, NULL,(void*)UpgradeParamSet_tcp, &(parambak)); if (nRet != 0){ printf("[%s] Failed to create UpgradeParamSet_thread\n", __FUNCTION__); } else { pthread_detach(clientTid); } pthread_mutex_unlock(&lock); } int main(){ printf("main start\r\n"); char msg1[1024]="hello ni hao"; char msg2[1024]="123456789"; char msg3[1024]="987654321"; char msg4[1024]="abcdef"; /* while(gflag == 1){ sleep(1); } UpgradeParamSet_thread(msg1); while(gflag == 1){ sleep(1); } UpgradeParamSet_thread(msg2); while(gflag == 1){ sleep(1); } UpgradeParamSet_thread(msg3); while(gflag == 1){ sleep(1); } UpgradeParamSet_thread(msg4); */ UpgradeParamSet_thread(msg1); UpgradeParamSet_thread(msg2); UpgradeParamSet_thread(msg3); UpgradeParamSet_thread(msg4); return 0; } |
|