因为线程的代码基本没怎么写过,leet-code出了线程题,刷下。
1116. 打印零与奇偶数
假设有这么一个类:
class ZeroEvenOdd {
public ZeroEvenOdd(int n) { ... } // 构造函数
public void zero(printNumber) { ... } // 仅打印出 0
public void even(printNumber) { ... } // 仅打印出 偶数
public void odd(printNumber) { ... } // 仅打印出 奇数
}
相同的一个 ZeroEvenOdd 类实例将会传递给三个不同的线程:
线程 A 将调用 zero(),它只输出 0 。
线程 B 将调用 even(),它只输出偶数。
线程 C 将调用 odd(),它只输出奇数。
每个线程都有一个 printNumber 方法来输出一个整数。请修改给出的代码以输出整数序列 010203040506... ,其中序列的长度必须为 2n。
示例 1:
输入:n = 2
输出:"0102"
说明:三条线程异步执行,其中一个调用 zero(),另一个线程调用 even(),最后一个线程调用odd()。正确的输出为 "0102"。
示例 2:
输入:n = 5
输出:"0102030405"
VERSION 1:
三锁版,lock1, lock2, lock3. 线程a 激活线程b或者c, 线程b, c 激活线程a
由于glibc的版本低,改了pthread_once
#define CHECK_VARIABLE(l,r) do{if(0 != r){fprintf(stderr,"[%s], err:[%d]
",l,r);break;}}while(0);
#define L pthread_mutex_t
#define LOCK(t) pthread_mutex_lock(&t)
#define UNLOCK(t) pthread_mutex_unlock(&t)
#if 0
pthread_once_t tOnce = PTHREAD_ONCE_INIT;
#endif
int g_iOnce = 0;
L tL0 = PTHREAD_MUTEX_INITIALIZER;
/* zero odd even */
L tL1;
L tL2;
L tL3;
void P(L* t)
{
while (pthread_mutex_lock(t) != 0) {}
return;
}
void V(L* t)
{
if (pthread_mutex_unlock(t) == -1) {
fprintf(stderr, "[%s].
", "pthread_mutex_unlock error.");
}
return;
}
typedef struct {
int n;
} ZeroEvenOdd;
ZeroEvenOdd* zeroEvenOddCreate(int n) {
ZeroEvenOdd* obj = (ZeroEvenOdd*) malloc(sizeof(ZeroEvenOdd));
obj->n = n;
return obj;
}
void threadOnceInit(){
int iRet = -1;
iRet = pthread_mutex_init(&tL1, NULL);
CHECK_VARIABLE("tL1 init error.", iRet);
iRet = pthread_mutex_init(&tL2, NULL);
CHECK_VARIABLE("tL1 init error.", iRet);
iRet = pthread_mutex_init(&tL3, NULL);
CHECK_VARIABLE("tL1 init error.", iRet);
P(&tL2);
P(&tL3);
return;
}
void zero(ZeroEvenOdd* obj) {
int iRet = 0;
int i = 0;
P(&tL0);
if (!g_iOnce)
{
threadOnceInit();
g_iOnce++;
}
V(&tL0);
#if 0
iRet = pthread_once(&tOnce, threadOnceInit);
CHECK_VARIABLE("pthread_once error.
", iRet);
#endif
for (; i < obj->n; i++)
{
P(&tL1);
printNumber(0);
if (i % 2)
{
V(&tL3);
}
else
{
V(&tL2);
}
}
pthread_exit(NULL);
}
void odd(ZeroEvenOdd* obj) {
int iRet = 0;
int i = 1;
P(&tL0);
if (!g_iOnce)
{
threadOnceInit();
g_iOnce++;
}
V(&tL0);
#if 0
iRet = pthread_once(&tOnce, threadOnceInit);
CHECK_VARIABLE("pthread_once error.
", iRet);
#endif
for (; i <= obj->n; i += 2)
{
P(&tL2);
printNumber(i);
V(&tL1);
}
pthread_exit(NULL);
}
void even(ZeroEvenOdd* obj) {
int iRet = 0;
int i = 2;
P(&tL0);
if (!g_iOnce)
{
threadOnceInit();
g_iOnce++;
}
V(&tL0);
#if 0
iRet = pthread_once(&tOnce, threadOnceInit);
CHECK_VARIABLE("pthread_once error.
", iRet);
#endif
for (; i <= obj->n; i += 2)
{
P(&tL3);
printNumber(i);
V(&tL1);
}
pthread_exit(NULL);
}
void zeroEvenOddFree(ZeroEvenOdd* obj) {
if (obj)
{
free(obj);
obj = NULL;
}
return;
}
高版本glibc支持pthread_once的code
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <stdint.h>
#include <math.h>
#include <pthread.h>
#include "leetcode.h"
/*
* leetcode 114:
* Level : mid
* 1116. Print Zero Even Odd
* realize by state var and semaphore
*/
#define CHECK_VARIABLE(l,r) do{if(0 != r){fprintf(stderr,"[%s], err:[%d]
",l,r);break;}}while(0);
#define SET_BIT(x, y) (x |= (1<<y))
#define NEG_BIT(x, y) (x ^= (1<<y))
#define GET_BIT(x, y) ((x)>>y & 0x1)
#define L pthread_mutex_t
#define LOCK(t) pthread_mutex_lock(&t)
#define UNLOCK(t) pthread_mutex_unlock(&t)
pthread_once_t tOnce = PTHREAD_ONCE_INIT;
/* zero odd even */
L tL1;
L tL2;
L tL3;
void P(L* t)
{
while (pthread_mutex_trylock(t) != 0) {}
return;
}
void V(L* t)
{
if (pthread_mutex_unlock(t) == -1) {
fprintf(stderr, "[%s].
", "pthread_mutex_unlock error.");
}
return;
}
void printNumber(int x)
{
printf("%d", x);
return;
}
typedef struct {
int n;
} ZeroEvenOdd;
ZeroEvenOdd* zeroEvenOddCreate(int n) {
ZeroEvenOdd* obj = (ZeroEvenOdd*) malloc(sizeof(ZeroEvenOdd));
obj->n = n;
return obj;
}
void threadOnceInit(){
int iRet = -1;
iRet = pthread_mutex_init(&tL1, NULL);
CHECK_VARIABLE("tL1 init error.", iRet);
iRet = pthread_mutex_init(&tL2, NULL);
CHECK_VARIABLE("tL1 init error.", iRet);
iRet = pthread_mutex_init(&tL3, NULL);
CHECK_VARIABLE("tL1 init error.", iRet);
P(&tL2);
P(&tL3);
return;
}
void zero(ZeroEvenOdd* obj) {
int iRet = 0;
int i = 0;
iRet = pthread_once(&tOnce, threadOnceInit);
CHECK_VARIABLE("pthread_once error.
", iRet);
for (; i < obj->n; i++)
{
P(&tL1);
printNumber(0);
if (i % 2)
{
V(&tL3);
}
else
{
V(&tL2);
}
}
pthread_exit(NULL);
}
void odd(ZeroEvenOdd* obj) {
int iRet = 0;
int i = 1;
iRet = pthread_once(&tOnce, threadOnceInit);
CHECK_VARIABLE("pthread_once error.
", iRet);
for (; i <= obj->n; i += 2)
{
P(&tL2);
printNumber(i);
V(&tL1);
}
pthread_exit(NULL);
}
void even(ZeroEvenOdd* obj) {
int iRet = 0;
int i = 2;
iRet = pthread_once(&tOnce, threadOnceInit);
CHECK_VARIABLE("pthread_once error.
", iRet);
for (; i <= obj->n; i += 2)
{
P(&tL3);
printNumber(i);
V(&tL1);
}
pthread_exit(NULL);
}
void zeroEvenOddFree(ZeroEvenOdd* obj) {
if (obj)
{
free(obj);
obj = NULL;
}
return;
}
#define RETURN_IF_ERR(ret)
if (0 != ret) {printf("Get errorcode = [%d] line = [%d].
", ret, __LINE__); return ret;}
int main()
{
int iRet = 0;
int* pvRet = NULL;
pthread_t tTid1 = 0;
pthread_t tTid2 = 0;
pthread_t tTid3 = 0;
ZeroEvenOdd* obj = NULL;
#if 1
obj = zeroEvenOddCreate(10);
RETURN_IF_ERR(obj == NULL);
iRet = pthread_create(&tTid1, NULL, zero, obj);
if (iRet) return iRet;
iRet = pthread_create(&tTid2, NULL, odd, obj);
if (iRet) return iRet;
iRet = pthread_create(&tTid3, NULL, even, obj);
if (iRet) return iRet;
iRet = pthread_join(tTid1, NULL);
RETURN_IF_ERR(iRet);
iRet = pthread_join(tTid2, NULL);
RETURN_IF_ERR(iRet);
iRet = pthread_join(tTid3, NULL);
RETURN_IF_ERR(iRet);
zeroEvenOddFree(obj);
pthread_mutex_destroy(&tL1);
pthread_mutex_destroy(&tL2);
pthread_mutex_destroy(&tL3);
#endif
return iRet;
}
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <stdint.h>
#include <math.h>
#include <pthread.h>
#include "leetcode.h"
#define CHECK_VARIABLE(l,r) do{if(0 != r){fprintf(stderr,"[%s], err:[%d]
",l,r);break;}}while(0);
#define SET_BIT(x, y) (x |= (1<<y))
#define NEG_BIT(x, y) (x ^= (1<<y))
#define GET_BIT(x, y) ((x)>>y & 0x1)
/*
* leetcode 114:
* Level : mid
* 1116. Print Zero Even Odd
* realize by state var and semaphore
*/
#define L pthread_mutex_t
#define LOCK(t) pthread_mutex_lock(&t)
#define UNLOCK(t) pthread_mutex_unlock(&t)
int g_iGuide = 0;
L tMutex;
pthread_once_t tOnce = PTHREAD_ONCE_INIT;
void P(L* t)
{
while (pthread_mutex_trylock(t) != 0) {}
return;
}
void V(L *t)
{
if (pthread_mutex_unlock(t) == -1) {
fprintf(stderr, "[%s].
", "pthread_mutex_unlock error.");
}
return;
}
void printNumber(int x)
{
printf("%d", x); return;
}
typedef struct {
int n;
} ZeroEvenOdd;
ZeroEvenOdd* zeroEvenOddCreate(int n) {
ZeroEvenOdd* obj = (ZeroEvenOdd*) malloc(sizeof(ZeroEvenOdd));
obj->n = n;
return obj;
}
void threadOnceInit(){
int iRet = -1;
iRet = pthread_mutex_init(&tMutex, NULL);
if (iRet) printf("pthread_mutex_init error.
");
return;
}
/* do like this 0x000, 0x010, 0x100 */
void zero(ZeroEvenOdd* obj) {
int iRet = 0;
int i = 0;
iRet = pthread_once(&tOnce, threadOnceInit);
CHECK_VARIABLE("pthread_once error.
", iRet);
while (1)
{
P(&tMutex);
if (GET_BIT(g_iGuide, 0)) {
V(&tMutex);
continue;
}
if (i < obj->n){
printNumber(0);
}
if (!GET_BIT(g_iGuide, 1)){ /* 000 -> 011 */
SET_BIT(g_iGuide, 1);
}
else if (!GET_BIT(g_iGuide, 2)){ /* 010 -> 111 */
SET_BIT(g_iGuide, 2);
}
else
{
sprintf(stderr, "[%s]
", "zero error.");
return;
}
SET_BIT(g_iGuide, 0);
V(&tMutex);
i = i + 1;
if (i > obj->n) break;
}
pthread_exit(NULL);
}
void odd(ZeroEvenOdd* obj) {
int iRet = 0;
int i = 1;
iRet = pthread_once(&tOnce, threadOnceInit);
CHECK_VARIABLE("pthread_once error.
", iRet);
while (1)
{
P(&tMutex);
if (!GET_BIT(g_iGuide, 0) || GET_BIT(g_iGuide, 2)) {
V(&tMutex);
continue;
}
if (i <= obj->n * 2)
{
printNumber((i + 1) / 2);
}
NEG_BIT(g_iGuide, 0); /* TODO: 010 -> 111 */
V(&tMutex);
i = i + 4;
if (i > obj->n * 2) break;
}
pthread_exit(NULL);
}
void even(ZeroEvenOdd* obj) {
int iRet = 0;
int i = 2;
iRet = pthread_once(&tOnce, threadOnceInit);
CHECK_VARIABLE("pthread_once error.
", iRet);
while (1)
{
P(&tMutex);
if (!GET_BIT(g_iGuide, 0) || !GET_BIT(g_iGuide, 2)) {
V(&tMutex);
continue;
}
if (i < obj->n * 2)
{
printNumber((i + 2) / 2);
}
g_iGuide = 0;
V(&tMutex);
i = i + 4;
if (i >= obj->n * 2) break;
}
pthread_exit(NULL);
}
void zeroEvenOddFree(ZeroEvenOdd* obj) {
if (obj)
{
free(obj);
obj = NULL;
}
return;
}
#define RETURN_IF_ERR(ret)
if (0 != ret) {printf("Get errorcode = [%d] line = [%d].
", ret, __LINE__); return ret;}
int main()
{
int iRet = 0;
int* pvRet = NULL;
pthread_t tTid1 = 0;
pthread_t tTid2 = 0;
pthread_t tTid3 = 0;
ZeroEvenOdd* obj = NULL;
#if 1
obj = zeroEvenOddCreate(10);
RETURN_IF_ERR(obj == NULL);
iRet = pthread_create(&tTid3, NULL, odd, obj);
if (iRet) return iRet;
iRet = pthread_create(&tTid2, NULL, even, obj);
if (iRet) return iRet;
iRet = pthread_create(&tTid1, NULL, zero, obj);
if (iRet) return iRet;
iRet = pthread_join(tTid3, NULL);
RETURN_IF_ERR(iRet);
iRet = pthread_join(tTid1, NULL);
RETURN_IF_ERR(iRet);
iRet = pthread_join(tTid2, NULL);
RETURN_IF_ERR(iRet);
zeroEvenOddFree(obj);
pthread_mutex_destroy(&tMutex);
#endif
return iRet;
}
使用 semaphore,不要问什么用这个,因为最早就是用semaphore,后发现测试机器不支持,才改用pthread_mutex_t
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <stdint.h>
#include <math.h>
#include <pthread.h>
#include <semaphore.h>
#include "leetcode.h"
#define CHECK_VARIABLE(l,r) do{if(0 != r){fprintf(stderr,"[%s], err:[%d]
",l,r);break;}}while(0);
#define SET_BIT(x, y) (x |= (1<<y))
#define NEG_BIT(x, y) (x ^= (1<<y))
#define GET_BIT(x, y) ((x)>>y & 0x1)
/*
* leetcode 114:
* Level : mid
* 1116. Print Zero Even Odd
* realize by state var and semaphore
*/
int g_iGuide = 0;
sem_t tSem;
pthread_once_t tOnce = PTHREAD_ONCE_INIT;
void P(sem_t* sem)
{
while (sem_wait(sem) != 0) {}
return;
}
void V(sem_t *sem)
{
if (sem_post(sem) == -1) {
fprintf(stderr, "[%s].
", "sem_post error.");
}
return;
}
void printNumber(int x)
{
printf("%d", x); return;
}
typedef struct {
int n;
} ZeroEvenOdd;
ZeroEvenOdd* zeroEvenOddCreate(int n) {
ZeroEvenOdd* obj = (ZeroEvenOdd*) malloc(sizeof(ZeroEvenOdd));
obj->n = n;
return obj;
}
void threadOnceInit(){
int iRet = -1;
iRet = sem_init(&tSem, 0, 1);
if (iRet) printf("sem_init error.
");
return;
}
/* do like this 0x000, 0x010, 0x100 */
void zero(ZeroEvenOdd* obj) {
int iRet = 0;
int i = 0;
iRet = pthread_once(&tOnce, threadOnceInit);
CHECK_VARIABLE("pthread_once error.
", iRet);
while (1)
{
P(&tSem);
if (GET_BIT(g_iGuide, 0)) {
V(&tSem);
continue;
}
if (i < obj->n){
printNumber(0);
}
if (!GET_BIT(g_iGuide, 1)){ /* 000 -> 011 */
SET_BIT(g_iGuide, 1);
}
else if (!GET_BIT(g_iGuide, 2)){ /* 010 -> 111 */
SET_BIT(g_iGuide, 2);
}
else
{
sprintf(stderr, "[%s]
", "zero error.");
return;
}
SET_BIT(g_iGuide, 0);
V(&tSem);
i = i + 1;
if (i > obj->n) break;
}
pthread_exit(NULL);
}
void odd(ZeroEvenOdd* obj) {
int iRet = 0;
int i = 1;
iRet = pthread_once(&tOnce, threadOnceInit);
CHECK_VARIABLE("pthread_once error.
", iRet);
while (1)
{
P(&tSem);
if (!GET_BIT(g_iGuide, 0) || GET_BIT(g_iGuide, 2)) {
V(&tSem);
continue;
}
if (i <= obj->n * 2)
{
printNumber((i + 1) / 2);
}
NEG_BIT(g_iGuide, 0); /* TODO: 010 -> 111 */
V(&tSem);
i = i + 4;
if (i > obj->n * 2) break;
}
pthread_exit(NULL);
}
void even(ZeroEvenOdd* obj) {
int iRet = 0;
int i = 2;
iRet = pthread_once(&tOnce, threadOnceInit);
CHECK_VARIABLE("pthread_once error.
", iRet);
while (1)
{
P(&tSem);
if (!GET_BIT(g_iGuide, 0) || !GET_BIT(g_iGuide, 2)) {
V(&tSem);
continue;
}
if (i < obj->n * 2)
{
printNumber((i + 2) / 2);
}
g_iGuide = 0;
V(&tSem);
i = i + 4;
if (i >= obj->n * 2) break;
}
pthread_exit(NULL);
}
void zeroEvenOddFree(ZeroEvenOdd* obj) {
if (obj)
{
free(obj);
obj = NULL;
}
return;
}
#define RETURN_IF_ERR(ret)
if (0 != ret) {printf("Get errorcode = [%d] line = [%d].
", ret, __LINE__); return ret;}
int main()
{
int iRet = 0;
int* pvRet = NULL;
pthread_t tTid1 = 0;
pthread_t tTid2 = 0;
pthread_t tTid3 = 0;
ZeroEvenOdd* obj = NULL;
#if 1
obj = zeroEvenOddCreate(10);
RETURN_IF_ERR(obj == NULL);
iRet = pthread_create(&tTid3, NULL, odd, obj);
if (iRet) return iRet;
iRet = pthread_create(&tTid2, NULL, even, obj);
if (iRet) return iRet;
iRet = pthread_create(&tTid1, NULL, zero, obj);
if (iRet) return iRet;
iRet = pthread_join(tTid3, NULL);
RETURN_IF_ERR(iRet);
iRet = pthread_join(tTid1, NULL);
RETURN_IF_ERR(iRet);
iRet = pthread_join(tTid2, NULL);
RETURN_IF_ERR(iRet);
zeroEvenOddFree(obj);
#endif
return iRet;
}
cond + mutex 最早用的,线程abc执行当满足条件时,否则竞争测试条件满足否。
void printNumber(int x)
{
printf("%d", x); return;
}
typedef struct {
int n;
} ZeroEvenOdd;
ZeroEvenOdd* zeroEvenOddCreate(int n) {
ZeroEvenOdd* obj = (ZeroEvenOdd*) malloc(sizeof(ZeroEvenOdd));
obj->n = n;
return obj;
}
int g_iCurIndex = -1;
pthread_mutex_t g_tMutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t g_tCond = PTHREAD_COND_INITIALIZER;
void zero(ZeroEvenOdd* obj) {
int iRet = 0;
while (1)
{
iRet = pthread_mutex_lock(&g_tMutex);
if (iRet) continue;
while (g_iCurIndex % 2 != 0)
{
pthread_cond_wait(&g_tCond, &g_tMutex);
}
if (g_iCurIndex == obj->n * 2)
{
g_iCurIndex = 0;
pthread_cond_broadcast(&g_tCond);
pthread_mutex_unlock(&g_tMutex);
/* free obj */
zeroEvenOddFree(obj);
break;
}
printNumber(0);
g_iCurIndex++;
pthread_mutex_unlock(&g_tMutex);
pthread_cond_broadcast(&g_tCond);
}
pthread_exit(NULL);
}
void odd(ZeroEvenOdd* obj) {
int iRet = 0;
while (1)
{
iRet = pthread_mutex_lock(&g_tMutex);
if (iRet) continue;
while ((g_iCurIndex % 2 == 0)
|| (g_iCurIndex % 4 != 1))
{
pthread_cond_wait(&g_tCond, &g_tMutex);
}
iRet = g_iCurIndex;
printNumber((iRet + 1) / 2);
g_iCurIndex++;
pthread_mutex_unlock(&g_tMutex);
pthread_cond_broadcast(&g_tCond);
if (iRet + 4 > obj->n * 2) break;
}
pthread_exit(NULL);
}
void even(ZeroEvenOdd* obj) {
int iRet = 0;
while (iRet = pthread_mutex_lock(&g_tMutex) != 0);
g_iCurIndex = 0;
pthread_mutex_unlock(&g_tMutex);
while (1)
{
iRet = pthread_mutex_lock(&g_tMutex);
if (iRet) continue;
while ((g_iCurIndex % 2 == 0)
|| (g_iCurIndex % 4 != 3))
{
pthread_cond_wait(&g_tCond, &g_tMutex);
if (g_iCurIndex == 0)
{
pthread_exit(NULL);
}
}
printNumber((g_iCurIndex + 1 ) / 2);
iRet = g_iCurIndex;
g_iCurIndex++;
pthread_mutex_unlock(&g_tMutex);
pthread_cond_broadcast(&g_tCond);
if (iRet + 4 > obj->n * 2) break;
}
pthread_exit(NULL);
}
void zeroEvenOddFree(ZeroEvenOdd* obj) {
if (obj)
{
free(obj);
obj = NULL;
}
return;
}