POSIX 线程,唯一执行
POSIX Threads, unique execution
有没有办法确保只有 1 个线程执行特定功能?
for (i = startnotfirst; i < end; i++) {
gl_rand = (float) lrand48();
fprintf(stderr, "\nTHREADING - #ID: %d - THIS IS MY RAND: %f", *mytid,rand);
to_open = (rand / (float) INT_MAX) < (points->p[i].cost / z);
if (to_open) {
//printf("\nRANDOM: %f \nINT_MAX: %d \npointsDistance(cost): %f \nZ: %f \n\n RESULT: %f < %f\n\n\n",rand ,INT_MAX,points->p[1].cost , z,(rand / (float) INT_MAX),(points->p[i].cost / z));
fprintf(stderr, "\nTHREADING - #ID: %d - im working...", *mytid);
t_kcenter++;
for (int k = start; k < end; k++) {
float distance = dist(points->p[i], points->p[k], points->dim);
//If distance is smaller add it to that cluster.
float new_cost = distance * points->p[k].weight;
if (new_cost < points->p[k].cost) {
points->p[k].cost = new_cost;
points->p[k].assign = i;
}
}
}
}
我希望 gl_rand 仅由一个线程执行,其他线程通过更改 global variable
或 broadcasting
.
了解新的 rand 值
另外线程必须在新数字出来之前都结束他们的工作iteration body
!
有什么想法吗?谢谢!
pthread_cond_wait()
和 pthread_cond_broadcast()
结合pthread_mutex_lock()
pthread_mutex_unlock()
,
pthread_cond_wait()
和
pthread_cond_broadcast()
函数是实现所需功能的关键。
但是,要使谓词正确,需要格外小心。
/*
** Objective: N threads cooperate on M cycles or iterations of a task.
** A new random number is needed for each cycle, but all threads must
** use the same random number on each cycle.
** Any thread may evaluate the new random number.
*/
#include <assert.h>
#include <errno.h>
#include <pthread.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "stderr.h"
#ifndef NUM_THREADS
#define NUM_THREADS 3
#endif
#ifndef NUM_CYCLES
#define NUM_CYCLES 5
#endif
enum { MAX_THREADS = NUM_THREADS };
enum { MAX_CYCLES = NUM_CYCLES };
static pthread_mutex_t mtx_waiting = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t cnd_waiting = PTHREAD_COND_INITIALIZER;
static int num_waiting = 0;
static int cycle = -1;
static float gl_rand = 0;
static long gl_long = 0;
static float next_iteration_random_number(int tid, int iteration)
{
pthread_mutex_lock(&mtx_waiting);
assert(cycle == iteration || cycle == iteration - 1);
num_waiting++;
printf("-->> TID %d, I = %d (C = %d, W = %d)\n",
tid, iteration, cycle, num_waiting);
while (cycle != iteration && num_waiting != MAX_THREADS)
{
assert(num_waiting > 0 && num_waiting <= MAX_THREADS);
printf("-CW- TID %d, I = %d (C = %d, W = %d)\n",
tid, iteration, cycle, num_waiting);
pthread_cond_wait(&cnd_waiting, &mtx_waiting);
}
assert(cycle == iteration || num_waiting == MAX_THREADS);
printf("---- TID %d, I = %d (C = %d, W = %d)\n",
tid, iteration, cycle, num_waiting);
if (cycle != iteration)
{
gl_long = lrand48();
gl_rand = (float)gl_long;
num_waiting = 0;
cycle = iteration;
printf("---- TID %d generates cycle %d: L = %ld, F = %g\n",
tid, cycle, gl_long, gl_rand);
pthread_cond_broadcast(&cnd_waiting);
}
printf("<<-- TID %d, I = %d (C = %d, W = %d) L = %ld, F = %g\n",
tid, iteration, cycle, num_waiting, gl_long, gl_rand);
pthread_mutex_unlock(&mtx_waiting);
return gl_rand;
}
static void *thread_function(void *vp)
{
int tid = (int)(uintptr_t)vp; // Thuggish!
for (int i = 0; i < MAX_CYCLES; i++)
{
float f = next_iteration_random_number(tid, i);
printf("TID %d at work: I = %d, F = %g\n", tid, i, f);
fflush(stdout);
struct timespec rq;
rq.tv_sec = 0;
rq.tv_nsec = (((gl_long & 0xFF) + (0xF * tid))) % 200 * 50000000;
assert(rq.tv_nsec >= 0 && rq.tv_nsec < 10000000000);
nanosleep(&rq, 0);
}
return 0;
}
int main(int argc, char **argv)
{
err_setarg0(argv[0]);
assert(argc == 1);
pthread_t thread[MAX_THREADS];
for (int i = 0; i < MAX_THREADS; i++)
{
int rc = pthread_create(&thread[i], 0, thread_function, (void *)(uintptr_t)i);
if (rc != 0)
{
errno = rc;
err_syserr("failed to create thread %d", i);
}
}
for (int i = 0; i < MAX_THREADS; i++)
{
void *vp;
int rc = pthread_join(thread[i], &vp);
if (rc != 0)
{
errno = rc;
err_syserr("Failed to join TID %d", i);
}
printf("TID %d returned %p\n", i, vp);
}
return 0;
}
来源GitHub. Library code in libsoq
。以 err_
开头的例程在 header stderr.h
中声明,支持代码在 stderr.c
中。这些大大简化了错误报告。
main()
函数很简单;它启动 5 个线程,然后等待加入 5 个线程。唯一棘手的一点是将线程号作为参数传递给线程函数。该代码将整数值转换为 uintptr_t
,然后将其强制转换为 void *
;被调用的函数撤销这个序列
per-thread函数并不复杂。它从它的参数中收集线程号,然后进入循环以迭代所需的循环数。在每次迭代中,它将迭代编号(和线程编号)传递给 next_iteration_random_number()
,它协调随机数生成。线程打印数据,然后使用 nanosleep()
休眠不到 1 秒的一段不易察觉的时间。
有趣的代码在next_iteration_random_number()
。首先,线程锁定控制共享信息的互斥量。然后它会增加等待线程的数量。如果当前循环与它正在处理的迭代不相同,并且等待线程数不等于线程总数,则该线程调用pthread_cond_wait()
休眠直到广播到。当线程退出循环时(通过在广播后醒来,或者因为它从未进入循环),线程会查看当前循环是否是它期望的迭代。如果不是,它一定是最后一个尝试此循环的线程——因此它生成随机数并进行内务处理以确保其他线程知道发生了什么,
然后它使用 pthread_cond_broadcast()
通知所有休眠线程唤醒。他们还不能真正醒来;当前线程仍然持有互斥量。它报告它正在做什么并解锁互斥锁,然后 returns 随机数。其他线程检测到循环数与它们等待的迭代相同,因此它们可以各自打印信息、解锁互斥锁和 return 数字。
关键是每个线程都必须知道它期望在哪个迭代上工作,并且当它还不是当前迭代时必须适当地休眠。代码中有大量的断言和打印操作,以帮助理解发生了什么。
完全分开,因为 lrand48()
return 是一个 long
(尽管值在 [0,231 范围内),所以它是一个 32 位值,即使 long
是 64 位类型),这意味着它 return 的值很有可能无法在 [=35= 中准确表示],因此从问题中截取的 gl_rand = (float)lrand48();
代码是可疑的。 (示例代码还将 long
值记录在 gl_long
中并偶尔使用它。)
代码在 Mac 运行ning macOS Sierra 10.12.3 和 GCC 6.3.0 上编译干净,编译选项设置为 fussy:
$ gcc -O3 -g -I../../inc -std=c11 -Wall -Wextra -Werror -Wmissing-prototypes \
> -Wstrict-prototypes -Wold-style-definition pthrd37.c -o pthrd37 \
> -L../../lib -lsoq
$
样本运行
配置了 3 个线程和 5 个周期的程序:
-->> TID 0, I = 0 (C = -1, W = 1)
-CW- TID 0, I = 0 (C = -1, W = 1)
-->> TID 2, I = 0 (C = -1, W = 2)
-CW- TID 2, I = 0 (C = -1, W = 2)
-->> TID 1, I = 0 (C = -1, W = 3)
---- TID 1, I = 0 (C = -1, W = 3)
---- TID 1 generates cycle 0: L = 851401618, F = 8.51402e+08
<<-- TID 1, I = 0 (C = 0, W = 0) L = 851401618, F = 8.51402e+08
TID 1 at work: I = 0, F = 8.51402e+08
---- TID 0, I = 0 (C = 0, W = 0)
<<-- TID 0, I = 0 (C = 0, W = 0) L = 851401618, F = 8.51402e+08
TID 0 at work: I = 0, F = 8.51402e+08
---- TID 2, I = 0 (C = 0, W = 0)
<<-- TID 2, I = 0 (C = 0, W = 0) L = 851401618, F = 8.51402e+08
TID 2 at work: I = 0, F = 8.51402e+08
-->> TID 1, I = 1 (C = 0, W = 1)
-CW- TID 1, I = 1 (C = 0, W = 1)
-->> TID 0, I = 1 (C = 0, W = 2)
-CW- TID 0, I = 1 (C = 0, W = 2)
-->> TID 2, I = 1 (C = 0, W = 3)
---- TID 2, I = 1 (C = 0, W = 3)
---- TID 2 generates cycle 1: L = 1804928587, F = 1.80493e+09
<<-- TID 2, I = 1 (C = 1, W = 0) L = 1804928587, F = 1.80493e+09
TID 2 at work: I = 1, F = 1.80493e+09
---- TID 1, I = 1 (C = 1, W = 0)
<<-- TID 1, I = 1 (C = 1, W = 0) L = 1804928587, F = 1.80493e+09
TID 1 at work: I = 1, F = 1.80493e+09
---- TID 0, I = 1 (C = 1, W = 0)
<<-- TID 0, I = 1 (C = 1, W = 0) L = 1804928587, F = 1.80493e+09
TID 0 at work: I = 1, F = 1.80493e+09
-->> TID 2, I = 2 (C = 1, W = 1)
-CW- TID 2, I = 2 (C = 1, W = 1)
-->> TID 1, I = 2 (C = 1, W = 2)
-CW- TID 1, I = 2 (C = 1, W = 2)
-->> TID 0, I = 2 (C = 1, W = 3)
---- TID 0, I = 2 (C = 1, W = 3)
---- TID 0 generates cycle 2: L = 758783491, F = 7.58783e+08
<<-- TID 0, I = 2 (C = 2, W = 0) L = 758783491, F = 7.58783e+08
TID 0 at work: I = 2, F = 7.58783e+08
---- TID 2, I = 2 (C = 2, W = 0)
<<-- TID 2, I = 2 (C = 2, W = 0) L = 758783491, F = 7.58783e+08
TID 2 at work: I = 2, F = 7.58783e+08
---- TID 1, I = 2 (C = 2, W = 0)
<<-- TID 1, I = 2 (C = 2, W = 0) L = 758783491, F = 7.58783e+08
TID 1 at work: I = 2, F = 7.58783e+08
-->> TID 0, I = 3 (C = 2, W = 1)
-CW- TID 0, I = 3 (C = 2, W = 1)
-->> TID 2, I = 3 (C = 2, W = 2)
-CW- TID 2, I = 3 (C = 2, W = 2)
-->> TID 1, I = 3 (C = 2, W = 3)
---- TID 1, I = 3 (C = 2, W = 3)
---- TID 1 generates cycle 3: L = 959030623, F = 9.59031e+08
<<-- TID 1, I = 3 (C = 3, W = 0) L = 959030623, F = 9.59031e+08
TID 1 at work: I = 3, F = 9.59031e+08
-->> TID 1, I = 4 (C = 3, W = 1)
-CW- TID 1, I = 4 (C = 3, W = 1)
---- TID 0, I = 3 (C = 3, W = 1)
<<-- TID 0, I = 3 (C = 3, W = 1) L = 959030623, F = 9.59031e+08
TID 0 at work: I = 3, F = 9.59031e+08
---- TID 2, I = 3 (C = 3, W = 1)
<<-- TID 2, I = 3 (C = 3, W = 1) L = 959030623, F = 9.59031e+08
TID 2 at work: I = 3, F = 9.59031e+08
-->> TID 0, I = 4 (C = 3, W = 2)
-CW- TID 0, I = 4 (C = 3, W = 2)
-->> TID 2, I = 4 (C = 3, W = 3)
---- TID 2, I = 4 (C = 3, W = 3)
---- TID 2 generates cycle 4: L = 684387517, F = 6.84388e+08
<<-- TID 2, I = 4 (C = 4, W = 0) L = 684387517, F = 6.84388e+08
TID 2 at work: I = 4, F = 6.84388e+08
---- TID 1, I = 4 (C = 4, W = 0)
<<-- TID 1, I = 4 (C = 4, W = 0) L = 684387517, F = 6.84388e+08
TID 1 at work: I = 4, F = 6.84388e+08
---- TID 0, I = 4 (C = 4, W = 0)
<<-- TID 0, I = 4 (C = 4, W = 0) L = 684387517, F = 6.84388e+08
TID 0 at work: I = 4, F = 6.84388e+08
TID 0 returned 0x0
TID 1 returned 0x0
TID 2 returned 0x0
注意每个线程碰巧至少生成一次随机数。这不是可以保证的事情,但它表明没有一个线程是特权的。
pthread_once()
此答案的第一个版本提到并说明了 pthread_once()
调用。这不是实际需要的,但是
它在其他情况下可能会有用。
假设你有一个足够POSIX-compliant的系统,如果你只想一个线程做某事,但哪个线程做并不重要,那么我相信你正在寻找pthread_once()
.
#include <pthread.h>
#include <stdlib.h>
static pthread_once_t once_only = PTHREAD_ONCE_INIT;
static float gl_rand = 0;
static void pt_once(void)
{
gl_rand = (float)lrand48();
}
void *thread_function(void *vp)
{
pthread_once(&once_only, pt_once);
…rest of the code…
return 0;
}
有没有办法确保只有 1 个线程执行特定功能?
for (i = startnotfirst; i < end; i++) {
gl_rand = (float) lrand48();
fprintf(stderr, "\nTHREADING - #ID: %d - THIS IS MY RAND: %f", *mytid,rand);
to_open = (rand / (float) INT_MAX) < (points->p[i].cost / z);
if (to_open) {
//printf("\nRANDOM: %f \nINT_MAX: %d \npointsDistance(cost): %f \nZ: %f \n\n RESULT: %f < %f\n\n\n",rand ,INT_MAX,points->p[1].cost , z,(rand / (float) INT_MAX),(points->p[i].cost / z));
fprintf(stderr, "\nTHREADING - #ID: %d - im working...", *mytid);
t_kcenter++;
for (int k = start; k < end; k++) {
float distance = dist(points->p[i], points->p[k], points->dim);
//If distance is smaller add it to that cluster.
float new_cost = distance * points->p[k].weight;
if (new_cost < points->p[k].cost) {
points->p[k].cost = new_cost;
points->p[k].assign = i;
}
}
}
}
我希望 gl_rand 仅由一个线程执行,其他线程通过更改 global variable
或 broadcasting
.
另外线程必须在新数字出来之前都结束他们的工作iteration body
!
有什么想法吗?谢谢!
pthread_cond_wait()
和 pthread_cond_broadcast()
结合pthread_mutex_lock()
pthread_mutex_unlock()
,
pthread_cond_wait()
和
pthread_cond_broadcast()
函数是实现所需功能的关键。
但是,要使谓词正确,需要格外小心。
/*
** Objective: N threads cooperate on M cycles or iterations of a task.
** A new random number is needed for each cycle, but all threads must
** use the same random number on each cycle.
** Any thread may evaluate the new random number.
*/
#include <assert.h>
#include <errno.h>
#include <pthread.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "stderr.h"
#ifndef NUM_THREADS
#define NUM_THREADS 3
#endif
#ifndef NUM_CYCLES
#define NUM_CYCLES 5
#endif
enum { MAX_THREADS = NUM_THREADS };
enum { MAX_CYCLES = NUM_CYCLES };
static pthread_mutex_t mtx_waiting = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t cnd_waiting = PTHREAD_COND_INITIALIZER;
static int num_waiting = 0;
static int cycle = -1;
static float gl_rand = 0;
static long gl_long = 0;
static float next_iteration_random_number(int tid, int iteration)
{
pthread_mutex_lock(&mtx_waiting);
assert(cycle == iteration || cycle == iteration - 1);
num_waiting++;
printf("-->> TID %d, I = %d (C = %d, W = %d)\n",
tid, iteration, cycle, num_waiting);
while (cycle != iteration && num_waiting != MAX_THREADS)
{
assert(num_waiting > 0 && num_waiting <= MAX_THREADS);
printf("-CW- TID %d, I = %d (C = %d, W = %d)\n",
tid, iteration, cycle, num_waiting);
pthread_cond_wait(&cnd_waiting, &mtx_waiting);
}
assert(cycle == iteration || num_waiting == MAX_THREADS);
printf("---- TID %d, I = %d (C = %d, W = %d)\n",
tid, iteration, cycle, num_waiting);
if (cycle != iteration)
{
gl_long = lrand48();
gl_rand = (float)gl_long;
num_waiting = 0;
cycle = iteration;
printf("---- TID %d generates cycle %d: L = %ld, F = %g\n",
tid, cycle, gl_long, gl_rand);
pthread_cond_broadcast(&cnd_waiting);
}
printf("<<-- TID %d, I = %d (C = %d, W = %d) L = %ld, F = %g\n",
tid, iteration, cycle, num_waiting, gl_long, gl_rand);
pthread_mutex_unlock(&mtx_waiting);
return gl_rand;
}
static void *thread_function(void *vp)
{
int tid = (int)(uintptr_t)vp; // Thuggish!
for (int i = 0; i < MAX_CYCLES; i++)
{
float f = next_iteration_random_number(tid, i);
printf("TID %d at work: I = %d, F = %g\n", tid, i, f);
fflush(stdout);
struct timespec rq;
rq.tv_sec = 0;
rq.tv_nsec = (((gl_long & 0xFF) + (0xF * tid))) % 200 * 50000000;
assert(rq.tv_nsec >= 0 && rq.tv_nsec < 10000000000);
nanosleep(&rq, 0);
}
return 0;
}
int main(int argc, char **argv)
{
err_setarg0(argv[0]);
assert(argc == 1);
pthread_t thread[MAX_THREADS];
for (int i = 0; i < MAX_THREADS; i++)
{
int rc = pthread_create(&thread[i], 0, thread_function, (void *)(uintptr_t)i);
if (rc != 0)
{
errno = rc;
err_syserr("failed to create thread %d", i);
}
}
for (int i = 0; i < MAX_THREADS; i++)
{
void *vp;
int rc = pthread_join(thread[i], &vp);
if (rc != 0)
{
errno = rc;
err_syserr("Failed to join TID %d", i);
}
printf("TID %d returned %p\n", i, vp);
}
return 0;
}
来源GitHub. Library code in libsoq
。以 err_
开头的例程在 header stderr.h
中声明,支持代码在 stderr.c
中。这些大大简化了错误报告。
main()
函数很简单;它启动 5 个线程,然后等待加入 5 个线程。唯一棘手的一点是将线程号作为参数传递给线程函数。该代码将整数值转换为 uintptr_t
,然后将其强制转换为 void *
;被调用的函数撤销这个序列
per-thread函数并不复杂。它从它的参数中收集线程号,然后进入循环以迭代所需的循环数。在每次迭代中,它将迭代编号(和线程编号)传递给 next_iteration_random_number()
,它协调随机数生成。线程打印数据,然后使用 nanosleep()
休眠不到 1 秒的一段不易察觉的时间。
有趣的代码在next_iteration_random_number()
。首先,线程锁定控制共享信息的互斥量。然后它会增加等待线程的数量。如果当前循环与它正在处理的迭代不相同,并且等待线程数不等于线程总数,则该线程调用pthread_cond_wait()
休眠直到广播到。当线程退出循环时(通过在广播后醒来,或者因为它从未进入循环),线程会查看当前循环是否是它期望的迭代。如果不是,它一定是最后一个尝试此循环的线程——因此它生成随机数并进行内务处理以确保其他线程知道发生了什么,
然后它使用 pthread_cond_broadcast()
通知所有休眠线程唤醒。他们还不能真正醒来;当前线程仍然持有互斥量。它报告它正在做什么并解锁互斥锁,然后 returns 随机数。其他线程检测到循环数与它们等待的迭代相同,因此它们可以各自打印信息、解锁互斥锁和 return 数字。
关键是每个线程都必须知道它期望在哪个迭代上工作,并且当它还不是当前迭代时必须适当地休眠。代码中有大量的断言和打印操作,以帮助理解发生了什么。
完全分开,因为 lrand48()
return 是一个 long
(尽管值在 [0,231 范围内),所以它是一个 32 位值,即使 long
是 64 位类型),这意味着它 return 的值很有可能无法在 [=35= 中准确表示],因此从问题中截取的 gl_rand = (float)lrand48();
代码是可疑的。 (示例代码还将 long
值记录在 gl_long
中并偶尔使用它。)
代码在 Mac 运行ning macOS Sierra 10.12.3 和 GCC 6.3.0 上编译干净,编译选项设置为 fussy:
$ gcc -O3 -g -I../../inc -std=c11 -Wall -Wextra -Werror -Wmissing-prototypes \
> -Wstrict-prototypes -Wold-style-definition pthrd37.c -o pthrd37 \
> -L../../lib -lsoq
$
样本运行
配置了 3 个线程和 5 个周期的程序:
-->> TID 0, I = 0 (C = -1, W = 1)
-CW- TID 0, I = 0 (C = -1, W = 1)
-->> TID 2, I = 0 (C = -1, W = 2)
-CW- TID 2, I = 0 (C = -1, W = 2)
-->> TID 1, I = 0 (C = -1, W = 3)
---- TID 1, I = 0 (C = -1, W = 3)
---- TID 1 generates cycle 0: L = 851401618, F = 8.51402e+08
<<-- TID 1, I = 0 (C = 0, W = 0) L = 851401618, F = 8.51402e+08
TID 1 at work: I = 0, F = 8.51402e+08
---- TID 0, I = 0 (C = 0, W = 0)
<<-- TID 0, I = 0 (C = 0, W = 0) L = 851401618, F = 8.51402e+08
TID 0 at work: I = 0, F = 8.51402e+08
---- TID 2, I = 0 (C = 0, W = 0)
<<-- TID 2, I = 0 (C = 0, W = 0) L = 851401618, F = 8.51402e+08
TID 2 at work: I = 0, F = 8.51402e+08
-->> TID 1, I = 1 (C = 0, W = 1)
-CW- TID 1, I = 1 (C = 0, W = 1)
-->> TID 0, I = 1 (C = 0, W = 2)
-CW- TID 0, I = 1 (C = 0, W = 2)
-->> TID 2, I = 1 (C = 0, W = 3)
---- TID 2, I = 1 (C = 0, W = 3)
---- TID 2 generates cycle 1: L = 1804928587, F = 1.80493e+09
<<-- TID 2, I = 1 (C = 1, W = 0) L = 1804928587, F = 1.80493e+09
TID 2 at work: I = 1, F = 1.80493e+09
---- TID 1, I = 1 (C = 1, W = 0)
<<-- TID 1, I = 1 (C = 1, W = 0) L = 1804928587, F = 1.80493e+09
TID 1 at work: I = 1, F = 1.80493e+09
---- TID 0, I = 1 (C = 1, W = 0)
<<-- TID 0, I = 1 (C = 1, W = 0) L = 1804928587, F = 1.80493e+09
TID 0 at work: I = 1, F = 1.80493e+09
-->> TID 2, I = 2 (C = 1, W = 1)
-CW- TID 2, I = 2 (C = 1, W = 1)
-->> TID 1, I = 2 (C = 1, W = 2)
-CW- TID 1, I = 2 (C = 1, W = 2)
-->> TID 0, I = 2 (C = 1, W = 3)
---- TID 0, I = 2 (C = 1, W = 3)
---- TID 0 generates cycle 2: L = 758783491, F = 7.58783e+08
<<-- TID 0, I = 2 (C = 2, W = 0) L = 758783491, F = 7.58783e+08
TID 0 at work: I = 2, F = 7.58783e+08
---- TID 2, I = 2 (C = 2, W = 0)
<<-- TID 2, I = 2 (C = 2, W = 0) L = 758783491, F = 7.58783e+08
TID 2 at work: I = 2, F = 7.58783e+08
---- TID 1, I = 2 (C = 2, W = 0)
<<-- TID 1, I = 2 (C = 2, W = 0) L = 758783491, F = 7.58783e+08
TID 1 at work: I = 2, F = 7.58783e+08
-->> TID 0, I = 3 (C = 2, W = 1)
-CW- TID 0, I = 3 (C = 2, W = 1)
-->> TID 2, I = 3 (C = 2, W = 2)
-CW- TID 2, I = 3 (C = 2, W = 2)
-->> TID 1, I = 3 (C = 2, W = 3)
---- TID 1, I = 3 (C = 2, W = 3)
---- TID 1 generates cycle 3: L = 959030623, F = 9.59031e+08
<<-- TID 1, I = 3 (C = 3, W = 0) L = 959030623, F = 9.59031e+08
TID 1 at work: I = 3, F = 9.59031e+08
-->> TID 1, I = 4 (C = 3, W = 1)
-CW- TID 1, I = 4 (C = 3, W = 1)
---- TID 0, I = 3 (C = 3, W = 1)
<<-- TID 0, I = 3 (C = 3, W = 1) L = 959030623, F = 9.59031e+08
TID 0 at work: I = 3, F = 9.59031e+08
---- TID 2, I = 3 (C = 3, W = 1)
<<-- TID 2, I = 3 (C = 3, W = 1) L = 959030623, F = 9.59031e+08
TID 2 at work: I = 3, F = 9.59031e+08
-->> TID 0, I = 4 (C = 3, W = 2)
-CW- TID 0, I = 4 (C = 3, W = 2)
-->> TID 2, I = 4 (C = 3, W = 3)
---- TID 2, I = 4 (C = 3, W = 3)
---- TID 2 generates cycle 4: L = 684387517, F = 6.84388e+08
<<-- TID 2, I = 4 (C = 4, W = 0) L = 684387517, F = 6.84388e+08
TID 2 at work: I = 4, F = 6.84388e+08
---- TID 1, I = 4 (C = 4, W = 0)
<<-- TID 1, I = 4 (C = 4, W = 0) L = 684387517, F = 6.84388e+08
TID 1 at work: I = 4, F = 6.84388e+08
---- TID 0, I = 4 (C = 4, W = 0)
<<-- TID 0, I = 4 (C = 4, W = 0) L = 684387517, F = 6.84388e+08
TID 0 at work: I = 4, F = 6.84388e+08
TID 0 returned 0x0
TID 1 returned 0x0
TID 2 returned 0x0
注意每个线程碰巧至少生成一次随机数。这不是可以保证的事情,但它表明没有一个线程是特权的。
pthread_once()
此答案的第一个版本提到并说明了 pthread_once()
调用。这不是实际需要的,但是
它在其他情况下可能会有用。
假设你有一个足够POSIX-compliant的系统,如果你只想一个线程做某事,但哪个线程做并不重要,那么我相信你正在寻找pthread_once()
.
#include <pthread.h>
#include <stdlib.h>
static pthread_once_t once_only = PTHREAD_ONCE_INIT;
static float gl_rand = 0;
static void pt_once(void)
{
gl_rand = (float)lrand48();
}
void *thread_function(void *vp)
{
pthread_once(&once_only, pt_once);
…rest of the code…
return 0;
}