线程冲突很常见。有效的解决办法,就是使用线程锁。
吾现在碰到一个问题:
多个数据线程向一个队列中添加数据。
一个执行线程负责处理队列中的数据。
开始使用线程锁,也没有问题。后来仔细想了一下,觉得此处有阻塞问题:
执行线程消耗时间较多,在执行前加锁,执行完毕后释放锁。
在执行线程加锁期间,数据线程等着向队列中添加数据,岂不是要等较长时间?
怎么办?吾想了个办法。原有代码保持不变,执行线程自己增加一个执行元素(用不着执行队列)。于是流程变为:
执行线程执行前,加锁。
将数据队列中最先加入的元素,复制成执行元素。
解锁。
执行线程处理执行元素。
这样不仅实现了线程安全,也保证各个线程的性能。实例代码如下:
/** 因为FEXT消耗时间较长,所以采取两个队列: 一个用来加数据,通过线程锁控制。 一个复制后,执行Fext */ static ImageBuffer** g_ppFextQueue = NULL; static int g_nFextQueueLength = -1; static pthread_mutex_t g_oFextMutext; static void fext_queue(ImageBuffer* pImage) { int queued = 0; //>=0表示初始化完成。 if (g_nFextQueueLength >= 0) { pthread_mutex_lock(&g_oFextMutext); if (g_nFextQueueLength >= GH_FEXT_QUEUE_LENGTH) { g_nFextQueueLength = 0; } //注意结构体内部的指针问题 memcpy(g_ppFextQueue[g_nFextQueueLength], pImage, sizeof(ImageBuffer)); g_nFextQueueLength ++; queued = 1; pthread_mutex_unlock(&g_oFextMutext); } if (!queued) { databuffer_release((DataBuffer*)&(pImage->buffer)); } } static void *fext_thread(void *arg) { int i; ImageBuffer* pFextExe = NULL; int queue_malloc_size = sizeof(ImageBuffer*)*GH_FEXT_QUEUE_LENGTH; //开始初始化,fext_queue()不会进行相应操作。 g_nFextQueueLength = -1; fext_init( (char*)arg); //free(arg); //fext初始化开始 pthread_mutex_init(&g_oFextMutext, NULL); g_ppFextQueue = (ImageBuffer**)gh_malloc(queue_malloc_size); for (i=0; i<GH_FEXT_QUEUE_LENGTH; i++) { g_ppFextQueue[i] = (ImageBuffer*)gh_malloc(sizeof(ImageBuffer)); } pFextExe = (ImageBuffer*)gh_malloc(sizeof(ImageBuffer)); //fext初始化完成 g_nFextQueueLength = 0; DataBuffer oImageFeature; memset(&oImageFeature, 0, sizeof(DataBuffer)); databuffer_check(&oImageFeature, sizeof(float)*GH_FEXT_FEATURE_SIZE); while (1) { if (g_nFextQueueLength == 0) { usleep(GH_FEXT_THREAD_SLEEP_TIME); continue; } //将数据队列的指针复制到执行队列。 pthread_mutex_lock( &g_oFextMutext); int early_index = g_nFextQueueLength + 1; //注意越界处理 memcpy(pFextExeQueue, g_ppFextQueue[early_index], sizeof(ImageBuffer)); g_nFextQueueLength = 0; pthread_mutex_unlock(&g_oFextMutext); fext_action(pImage, &oImageFeature); } //做个样子而已。 databuffer_release(&oImageFeature); free_array(g_ppFextQueue, GH_FEXT_QUEUE_LENGTH); free(g_ppFextQueue); free(pFextExeQueue); }