当一个全局资源被多个线程访问且面临竞争时,需要互斥锁来解决这一竞争问题来保证访问这一全局资源的原子性即数据独立性不被破坏,也就是说并不是有多个线程访问同一全局资源就需要使用互斥锁,如果多线程在访问同一全局变量时因为逻辑关系而不会产生资源竞争问题,此时无需互斥锁,因为各自线程在访问全局资源时不会被其他线程所干预即不面临竞争关系,也就是说全局资源在被任意线程访问时期间是独立性,确保数据访问是原子的。
当全局资源被多线程访问时,线程对全局资源读的次数远大于写次数时,我们应该用读写锁来代替互斥锁以提高效率,根据读写锁特征:当读写锁以读模式锁住时,它是以共享模式锁住资源的,即多个线程可以同时以读方式获取该资源,而以写模式锁住时,它是以独占模式锁住,不像互斥锁那样一旦线程获取到互斥锁,其他线程处于阻塞状态直到获得互斥锁线程解锁。换句话说,读写锁可以被多个线程以读模式获取,而互斥锁任何时候只能被一个线程获取。下面以代码来说明:
不使用互斥锁多线访问同一全局资源情形:
static int count_operator(const char *name)
{
int i = 0;
for(i = 0; i < 20; i++)
{
if(gs32_count < 55)
{
usleep(10 * 1000);
gs32_count++;
printf("[%s] gs32_count:%d\n", name, gs32_count);
}
usleep(1 * 1000 * 1000);
}
return 0;
}
static void test1_task(void *arg)
{
count_operator("test1");
pthread_exit(0);
}
static void test2_task(void *arg)
{
count_operator("test2");
pthread_exit(0);
}
int call_test_a(void)
{
tthread test1;
test1.init("test1",test1_task,NULL);
test1.start();
tthread test2;
test2.init("test2",test2_task,NULL);
test2.start();
count_operator("main");
sleep(3);
return 0;
}
运行结果时:全局变量gs32_count最终为57,程序设计意图是55。
多线程使用互斥锁访问全局资源情形:
static int gs32_count = 0;
static tmutex g_count_mutex;
static int count_operator(const char *name)
{
int i = 0;
for(i = 0; i < 20; i++)
{
g_count_mutex.lock();
if(gs32_count < 55)
{
usleep(10 * 1000);
gs32_count++;
printf("[%s] gs32_count:%d\n", name, gs32_count);
}
g_count_mutex.unlock();
usleep(1 * 1000 * 1000);
}
return 0;
}
static void test1_task(void *arg)
{
count_operator("test1");
pthread_exit(0);
}
static void test2_task(void *arg)
{
count_operator("test2");
pthread_exit(0);
}
int call_test_b(void)
{
tthread test1;
test1.init("test1",test1_task,NULL);
test1.start();
tthread test2;
test2.init("test2",test2_task,NULL);
test2.start();
count_operator("main");
sleep(3);
return 0;
}
运行结果:全局变量gs32_count最终为55,符合程序设计意图。
多线程以读写锁方式访问全局资源情形:
static int gs32_data = 0;
Static xrwlock g_data_rwlock;
static int read_data(const char *name)
{
int i = 0;
for(i = 0; i < 20; i++)
{
g_data_rwlock.rdlock();
if(gs32_data < 10)
{
printf("[%s] gs32_count:%d\n", name, gs32_data);
}
g_data_rwlock.unlock();
usleep(1 * 1000 * 1000);
}
return 0;
}
static int write_data(const char *name)
{
int i = 0;
for(i = 0; i < 20; i++)
{
g_data_rwlock.wrlock();
gs32_data++;
printf("[%s] gs32_count:%d\n", name, gs32_data);
g_data_rwlock.unlock();
usleep(1 * 1000 * 1000);
}
return 0;
}
static void test1_task(void *arg)
{
read_data("test1");
pthread_exit(0);
}
static void test2_task(void *arg)
{
write_data("test2");
pthread_exit(0);
}
int call_test_c(void)
{
tthread thread_test1, thread_test2;
thread_test1.init("test1", test1_task, NULL);
thread_test2.init("test2", test2_task, NULL);
thread_test1.start();
thread_test2.start();
read_data("main");
sleep(3);
return 0;
}
线程test2对全局变量gs32_data以写模式访问,线程test1和主线程以读模式访问全局变量gs32_data,如果使用互斥锁的话将会降低程序运行效率,特别当线程读模式访问远大于写模式访问时。