迅雷笔试题:
编写一个程序,开启3个线程,这3个线程的ID分别为A、B、C,每个线程将自己的ID在屏幕上打印10遍,要求输出结果必须按ABC的顺序显示;如:ABCABC….依次递推。
Windows(VC9下编译运行通过):
#include <iostream>
#include <windows.h>
#include <process.h>
using namespace std;
#define PRINT_TIMES 10
// 考虑到可读性 多写几个handle
// #define THREAD_NUMS 3
// 用于打印字符控制,有点类似循环链表
struct sPrintControl
{
char cPrint;
HANDLE hEventThis;
HANDLE hEventNext;
};
// 按照顺序打印字符
UINT WINAPI vPrintCharWithSeq(LPVOID p_psPrintControl)
{
sPrintControl* l_psPrintControl = static_cast<sPrintControl*>(p_psPrintControl);
char l_cChar = l_psPrintControl->cPrint;
for (int i = 0; i < PRINT_TIMES; i++)
{
// wait for print
WaitForSingleObject(l_psPrintControl->hEventThis, INFINITE);
cout<<"ThreadId:"<<GetCurrentThreadId()<<' '<<i<<l_cChar<<endl;
// signal the next thread
SetEvent(l_psPrintControl->hEventNext);
}
return 0;
}
int main()
{
HANDLE l_hThreadA = NULL;
HANDLE l_hThreadB = NULL;
HANDLE l_hThreadC = NULL;
HANDLE l_hThreadAEvent = NULL;
HANDLE l_hThreadBEvent = NULL;
HANDLE l_hThreadCEvent = NULL;
// 自动重置,从ThreadA开始打印
l_hThreadAEvent = CreateEvent(NULL, FALSE, TRUE, NULL);
l_hThreadBEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
l_hThreadCEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
sPrintControl l_sPrintControl[3] = {
{'A', l_hThreadAEvent, l_hThreadBEvent},
{'B', l_hThreadBEvent, l_hThreadCEvent},
{'C', l_hThreadCEvent, l_hThreadAEvent}
};
l_hThreadA = (HANDLE)_beginthreadex(NULL, 0, vPrintCharWithSeq, &l_sPrintControl[0], THREAD_PRIORITY_NORMAL, NULL);
l_hThreadB = (HANDLE)_beginthreadex(NULL, 0, vPrintCharWithSeq, &l_sPrintControl[1], THREAD_PRIORITY_NORMAL, NULL);
l_hThreadC = (HANDLE)_beginthreadex(NULL, 0, vPrintCharWithSeq, &l_sPrintControl[2], THREAD_PRIORITY_NORMAL, NULL);
// 等待线程结束
WaitForSingleObject(l_hThreadA, INFINITE);
WaitForSingleObject(l_hThreadB, INFINITE);
WaitForSingleObject(l_hThreadC, INFINITE);
// 释放
CloseHandle(l_hThreadA);
CloseHandle(l_hThreadB);
CloseHandle(l_hThreadC);
CloseHandle(l_hThreadAEvent);
CloseHandle(l_hThreadBEvent);
CloseHandle(l_hThreadCEvent);
return 0;
}
Linux:
感谢Jinhao的帮助。用pthread_cond_t解决了。实际上测试用sem_t还快一点。因为用sem_t的方法类似windows下面用Event就不贴代码了。
线程关键代码:
void * thread(thr_id* t)
{
pthread_mutex_lock(t->mutex); //这个lock相当重要
sem_post(t->sem);
pthread_cond_wait(t->self_cond, t->mutex);
pthread_mutex_unlock(t->mutex);
//真正开始
for(int i = 0; i < 10; ++i)
{
pthread_mutex_lock(t->mutex);
std::cout<<t->id<<std::flush;
pthread_cond_signal(t->next_cond);
if(i < 9) //输出最后一遍的时候,不用再wait而是退出线程
pthread_cond_wait(t->self_cond, t->mutex);
pthread_mutex_unlock(t->mutex);
}
}
Jinhao:现在C唤醒A的时候,能保证A是wait的状态.因为A在cond_wait的时候,B才能获得锁,当b在cond_wait的时候,C才获得锁.所以当C cond_signal A时, A必然是cond_wait的。
全部代码如下:
#include <iostream>
#include <stdlib.h>
#include <pthread.h>
#include <stdio.h>
#include <semaphore.h>
using namespace std;
struct thr_id
{
char id;
sem_t * sem;
pthread_mutex_t * mutex;
pthread_cond_t * self_cond;
pthread_cond_t * next_cond;
};
void * thread(thr_id* t)
{
pthread_mutex_lock(t->mutex);
sem_post(t->sem);
pthread_cond_wait(t->self_cond, t->mutex);
pthread_mutex_unlock(t->mutex);
for(int i = 0; i < 10000; ++i)
{
pthread_mutex_lock(t->mutex);
std::cout<<t->id<<std::flush;
pthread_cond_signal(t->next_cond);
if(i < 9999)
pthread_cond_wait(t->self_cond, t->mutex);
pthread_mutex_unlock(t->mutex);
}
}
typedef void* (*PRINTTHREADFUNC) (void*);
int main()
{
pthread_t th_a, th_b, th_c;
sem_t sem;
sem_init(&sem, 0, 0);
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond_a = PTHREAD_COND_INITIALIZER;
pthread_cond_t cond_b = PTHREAD_COND_INITIALIZER;
pthread_cond_t cond_c = PTHREAD_COND_INITIALIZER;
thr_id thrids[3] = {
{'a', &sem, &mutex, &cond_a, &cond_b},
{'b', &sem, &mutex, &cond_b, &cond_c},
{'c', &sem, &mutex, &cond_c, &cond_a}
};
pthread_create(&th_a, NULL, reinterpret_cast<PRINTTHREADFUNC>(thread), &thrids[0]);
pthread_create(&th_b, NULL, reinterpret_cast<PRINTTHREADFUNC>(thread), &thrids[1]);
pthread_create(&th_c, NULL, reinterpret_cast<PRINTTHREADFUNC>(thread), &thrids[2]);
for(int i = 0; i < 3; ++i)
{
sem_wait(&sem);
}
pthread_mutex_lock(&mutex);
pthread_cond_signal(thrids[0].self_cond);
pthread_mutex_unlock(&mutex);
pthread_join(th_a, NULL);
pthread_join(th_b, NULL);
pthread_join(th_c, NULL);
sem_destroy(&sem);
pthread_cond_destroy(&cond_a);
pthread_cond_destroy(&cond_b);
pthread_cond_destroy(&cond_c);
return 0;
}