- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
基本上,我的程序创建了 3 个线程。 “服务器”和 2 个“ worker ”。工作人员旨在对 1000 行文件(每个线程 500 个数字)中的 3 位正整数求和。在每个 worker 对自己的部分求和后,服务器打印每个 worker 的总数。唯一的问题是我的信号量似乎不起作用。
这是我的程序的一个版本:
// simple c program to simulate POSIX thread and semaphore
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <semaphore.h>
// define semaphores
sem_t s1;
FILE *file;
int sum1 = 0, sum2 = 0, num1 = 0, num2 = 0;
// file name
char fileName[10] = "data1.dat";
// server routine
void* server_routine()
{
printf("Server sent signal to worker thread 1\n");
printf("Server sent signal to worker thread 2\n");
sem_wait(&s1);
printf("Server recieved completion signal from worker thread 1\n");
sem_wait(&s1);
printf("Server recieved completion signal from worker thread 2\n\n");
// print the final results
printf("The sum of the first 500 numbers in the file is: %d\n", sum1);
printf("The sum of the last 500 numbers in the file is: %d\n\n", sum2);
pthread_exit(NULL);
}
// thread 1 reoutine
void* t1_routine()
{
printf("Thread 1 recieved signal from server\n");
file = fopen(fileName, "r");
for(int i = 0; i < 500; i++)
{
fscanf(file, "%d", &num1);
sum1 += num1;
}
printf("sum in thread 1: %d\n", sum1);
printf("Thread 1 sends completion signal to server\n");
sem_post(&s1);
pthread_exit(NULL);
}
// thread 2 routine
void* t2_routine()
{
printf("Thread 2 recieved signal from server\n");
file = fopen(fileName, "r");
fseek(file, 500 * 5, SEEK_SET);
for(int i = 0; i < 500; i++)
{
fscanf(file, "%d", &num2);
sum2 += num2;
}
printf("sum in thread 2: %d\n", sum2);
printf("Thread 2 sends completion signal to server\n");
sem_post(&s1);
pthread_exit(NULL);
}
// main function
int main(int argc, char *argv[])
{
// define threads
pthread_t server, t1, t2;
// initialize the semaphore
sem_init(&s1, 0, 0);
if(pthread_create(&server, NULL, &server_routine, NULL) != 0)
{
return 1;
}
if(pthread_create(&t1, NULL, &t1_routine, NULL) != 0)
{
return 2;
}
if(pthread_create(&t2, NULL, &t2_routine, NULL) != 0)
{
return 3;
}
if(pthread_join(server, NULL) != 0)
{
return 4;
}
if(pthread_join(t1, NULL) != 0)
{
return 5;
}
if(pthread_join(t2, NULL) != 0)
{
return 6;
}
// destroy semaphores
sem_close(&s1);
// exit thread
pthread_exit(NULL);
// end
return 0;
}
我也用更少的线程测试了更多的信号量,但运气不佳。我尝试过不同的初始信号量值。我唯一可以获得正确输出的时间是手动等待 sleep(5);但这违背了这个项目的目的。
最佳答案
几个问题...
fopen
但是FILE *file;
是global 所以它们覆盖彼此重视。fclose
调用。pthread_exit
应该不 由主 线程完成。它仅适用于使用 pthread_create
创建的线程。否则……
fopen
last 的线程将设置最终值。pthread_create
调用之前)完成了单个 fopen
,违背了每个线程执行自己的 fopen
的目的。fopen
,然后从fscanf
开始并拥有它的文件
当 second 线程替换 file
值时值发生变化,因此每个线程都会发生奇怪的事情,因为它们正在 fseek/fscanf
< em>相同 FILE *
实例。fclose
调用会使问题更加明显。这是重构后的代码。它被注释:
// simple c program to simulate POSIX thread and semaphore
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <semaphore.h>
// define semaphores
sem_t s1;
// NOTE/BUG: each thread opens a different stream, so this must be function
// scoped
#if 0
FILE *file;
#endif
int sum1 = 0,
sum2 = 0,
num1 = 0,
num2 = 0;
// file name
char fileName[10] = "data1.dat";
// server routine
void *
server_routine()
{
printf("Server sent signal to worker thread 1\n");
printf("Server sent signal to worker thread 2\n");
sem_wait(&s1);
printf("Server recieved completion signal from worker thread 1\n");
sem_wait(&s1);
printf("Server recieved completion signal from worker thread 2\n\n");
// print the final results
printf("The sum of the first 500 numbers in the file is: %d\n", sum1);
printf("The sum of the last 500 numbers in the file is: %d\n\n", sum2);
pthread_exit(NULL);
}
// thread 1 reoutine
void *
t1_routine()
{
// NOTE/FIX: this must be function scoped (i.e. private to this thread)
#if 1
FILE *file;
#endif
printf("Thread 1 recieved signal from server\n");
file = fopen(fileName, "r");
for (int i = 0; i < 500; i++) {
fscanf(file, "%d", &num1);
sum1 += num1;
}
printf("sum in thread 1: %d\n", sum1);
printf("Thread 1 sends completion signal to server\n");
sem_post(&s1);
#if 1
fclose(file);
#endif
pthread_exit(NULL);
}
// thread 2 routine
void *
t2_routine()
{
// NOTE/FIX: this must be function scoped (i.e. private to this thread)
#if 1
FILE *file;
#endif
printf("Thread 2 recieved signal from server\n");
file = fopen(fileName, "r");
fseek(file, 500 * 5, SEEK_SET);
for (int i = 0; i < 500; i++) {
fscanf(file, "%d", &num2);
sum2 += num2;
}
printf("sum in thread 2: %d\n", sum2);
printf("Thread 2 sends completion signal to server\n");
sem_post(&s1);
#if 1
fclose(file);
#endif
pthread_exit(NULL);
}
// main function
int
main(int argc, char *argv[])
{
// define threads
pthread_t server, t1, t2;
// initialize the semaphore
sem_init(&s1, 0, 0);
if (pthread_create(&server, NULL, &server_routine, NULL) != 0) {
return 1;
}
if (pthread_create(&t1, NULL, &t1_routine, NULL) != 0) {
return 2;
}
if (pthread_create(&t2, NULL, &t2_routine, NULL) != 0) {
return 3;
}
if (pthread_join(server, NULL) != 0) {
return 4;
}
if (pthread_join(t1, NULL) != 0) {
return 5;
}
if (pthread_join(t2, NULL) != 0) {
return 6;
}
// destroy semaphores
sem_close(&s1);
// exit thread
// NOTE/BUG: only a subthread should do this
#if 0
pthread_exit(NULL);
#endif
// end
return 0;
}
在上面的代码中,我使用了 cpp
条件来表示旧代码与新代码:
#if 0
// old code
#else
// new code
#endif
#if 1
// new code
#endif
注意:这可以通过 unifdef -k
更新:
Thank you for the response Craig. I have implemented your suggestions to my own code but nothing seemed to change. I then decided to copy paste your updated code into a c file to test it out and I got the same result. It is as follows (in a separate comment since the output is too long): – Max
很难比较结果,因为我们使用的是不同的数据集。我创建了一个 perl
脚本来创建一些数据。
最重要的是给定工作人员报告的总和与服务器看到的该工作人员任务的总和相匹配。
然后,如果我们知道文件的每个线程部分的总和应该是多少,那就是另一回事了。
每行终止是关键的(例如):CRLF 与 LF(见下文)
worker sem_post
和终止的实际顺序并不重要。它可以因系统而异,甚至可以因调用而异。重要的是服务器线程在打印任何总和之前等待 N 个线程(即)N 个 sem_wait
调用。
我在下面制作了一个更新版本。
sem_post
向服务器“发送信号”,服务器通过执行 sem_wait
struct
来保存总和、线程 ID 等。\n
位置的检查(即线宽)。也就是说,在 linux/POSIX 下,四位数字后跟 LF(换行符),长度为 5。但是,在 Windows 下,它将是 CRLF(回车/换行符),长度为 6。这是更新后的代码:
// simple c program to simulate POSIX thread and semaphore
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <semaphore.h>
#include <sys/stat.h>
// number of bytes per line
// 5: 4 digits + LF
// 6: 4 digits + CRLF
#ifndef LINEWID
#define LINEWID (4 + 1)
#endif
// number of items / task
#ifndef COUNT
#define COUNT 500
#endif
// define semaphores
sem_t s1;
#if 0
int sum1 = 0,
sum2 = 0,
num1 = 0,
num2 = 0;
#endif
// file name
#if 0
char fileName[10] = "data1.dat";
#else
const char *fileName = "data1.dat";
#endif
// task control
typedef struct {
pthread_t tid; // thread ID
int tno; // thread index/offset
int sum; // sum
} tsk_t;
#define TSKMAX 50
int tskmax; // actual number of tasks
tsk_t tsklist[TSKMAX]; // list of tasks
// loop through all task blocks
#define TSKFORALL \
tsk_t *tsk = &tsklist[0]; tsk < &tsklist[tskmax]; ++tsk
// server routine
void *
server_routine(void *vp)
{
// NOTE/BUG: server does _not_ signal worker
#if 0
printf("Server sent signal to worker thread 1\n");
printf("Server sent signal to worker thread 2\n");
#endif
for (TSKFORALL) {
printf("Server waiting ...\n");
sem_wait(&s1);
printf("Server complete ...\n");
}
// print the final results
for (TSKFORALL)
printf("The sum of task %d is %d\n",tsk->tno,tsk->sum);
return (void *) 0;
}
// thread 1 reoutine
void *
worker_routine(void *vp)
{
FILE *file;
tsk_t *tsk = vp;
printf("Thread %d running ...\n",tsk->tno);
file = fopen(fileName, "r");
fseek(file,tsk->tno * COUNT * LINEWID,SEEK_SET);
tsk->sum = 0;
int num1;
int first = -1;
int last = -1;
for (int i = 0; i < COUNT; i++) {
if (fscanf(file, "%d", &num1) != 1) {
printf("Thread %d fscan error\n",tsk->tno);
break;
}
if (i == 0)
first = num1;
if (i == (COUNT - 1))
last = num1;
tsk->sum += num1;
}
printf("sum in thread %d: %d (first %d, last %d)\n",
tsk->tno, tsk->sum, first, last);
sem_post(&s1);
#if 1
fclose(file);
#endif
return (void *) 0;
}
// main function
int
main(int argc, char **argv)
{
--argc;
++argv;
setlinebuf(stdout);
setlinebuf(stderr);
if (argc != 1)
tskmax = 2;
else
tskmax = atoi(*argv);
if (tskmax > TSKMAX)
tskmax = TSKMAX;
// define threads
pthread_t server;
printf("main: %d tasks\n",tskmax);
printf("main: %d count\n",COUNT);
FILE *file = fopen(fileName,"r");
if (file == NULL) {
printf("main: fopen failure\n");
exit(96);
}
// check alignment
char chr;
fseek(file,LINEWID - 1,0);
fread(&chr,1,1,file);
if (chr != '\n') {
printf("main: newline mismatch -- chr=%2.2X\n",chr);
exit(97);
}
// get the file size
struct stat st;
if (fstat(fileno(file),&st) < 0) {
printf("main: fstat fault\n");
exit(97);
}
// ensure the file has the correct size
off_t size = tskmax * LINEWID * COUNT;
if (st.st_size != size)
printf("main: wrong file size -- st_size=%llu size=%llu\n",
(unsigned long long) st.st_size,
(unsigned long long) size);
fclose(file);
// initialize the semaphore
sem_init(&s1, 0, 0);
// set the offsets
int tno = 0;
for (TSKFORALL, ++tno)
tsk->tno = tno;
if (pthread_create(&server, NULL, &server_routine, NULL) != 0)
return 98;
for (TSKFORALL) {
if (pthread_create(&tsk->tid,NULL,worker_routine,tsk) != 0)
return 1 + tsk->tno;
}
if (pthread_join(server, NULL) != 0) {
return 99;
}
for (TSKFORALL) {
if (pthread_join(tsk->tid, NULL) != 0) {
return 5;
}
}
// destroy semaphores
sem_close(&s1);
// end
return 0;
}
这是我用来生成数据的 perl 脚本输出:
number of tasks 2
element count per task 500
line separater 0A
section 0 sum 124750
section 1 sum 125250
程序输出如下:
main: 2 tasks
Server waiting ...
Thread 0 running ...
Thread 1 running ...
sum in thread 1: 125250 (first 1, last 500)
sum in thread 0: 124750 (first 0, last 499)
Server complete ...
Server waiting ...
Server complete ...
The sum of task 0 is 124750
The sum of task 1 is 125250
这是 perl
脚本:
#!/usr/bin/perl
# gendata -- generate data
#
# arguments:
# 1 - number of tasks (DEFAULT: 2)
# 2 - number of items / task (DEFAULT: 500)
# 3 - line separater (DEFAULT: \n)
master(@ARGV);
exit(0);
# master -- master control
sub master
{
my(@argv) = @_;
$tskmax = shift(@argv);
$tskmax //= 2;
printf(STDERR "number of tasks %d\n",$tskmax);
$count = shift(@argv);
$count //= 500;
printf(STDERR "element count per task %d\n",$count);
$sep = shift(@argv);
$sep //= "\n";
printf(STDERR "line separater");
foreach $chr (split(//,$sep)) {
$hex = ord($chr);
printf(STDERR " %2.2X",$hex);
}
printf(STDERR "\n");
for ($itsk = 0; $itsk < $tskmax; ++$itsk) {
$val = $itsk;
$sum = 0;
for ($lno = 1; $lno <= $count; ++$lno, ++$val) {
printf("%4d%s",$val,$sep);
$sum += $val;
}
printf(STDERR "section %d sum %d\n",$itsk,$sum);
}
}
关于c - 为什么我的程序在调用 sem_wait 时不等待?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/74695532/
我这里有一个相当奇怪的问题,或者我不知道它的工作方式,但是我有下面的程序可以正确创建信号量并第一次运行到最后。但是在 sem_wait 处出现 SEGFault,如果信号量已经存在。我在 64 位 F
跟进我之前的问题: Conditional wait with pthreads 我将代码更改为使用信号量而不是互斥锁和条件信号。但是,我似乎遇到了无法解释的情况。 这是摘要 function thr
我用 C 编写了一个通用队列,用于各种负载类型。它是一个阻塞队列,因此消费者线程将阻塞等待队列被生产者线程填充。 我已经使用 check 单独测试了队列代码,包括线程阻塞等待将值添加到队列的行为。所有
我有一个进程生成了几个子进程。它们都共享一个信号量。 在我的主程序中。 sem_t *sharedSem = sem_open(SHAREDSEM, O_CREAT, 0600, 4); // Ini
我真正想知道的是sem_wait()是否是“不忙等待”。如果线程在 sem_wait() 中等待其请求的资源,是否会浪费 CPU 周期。 最佳答案 通常,同步原语将线程添加到等待队列,然后将其置于 s
这是我的生产者和消费者问题的代码。它可以被编译,但是当我运行程序时它什么也不打印。我测试了程序,发现问题可能与 sem_wait() 有关。为什么程序可以编译但输出错误?谢谢。 int main(in
有什么办法可以让我在同一个互斥锁中拥有最多 10 个线程? 类似于 sem_wait() 的值 10。 编辑: 找到这个: 它是信号量的一个实现,使用了互斥量和条件变量。 typedef struct
我编写了这个创建子进程并在其中打印一些消息的简单程序: #include #include #include #include #include #include #include se
用 gcc 编译。我运行它来查看为什么我在其他程序中使用的信号量无法正常工作。我只是错误地使用了它们还是什么?即使信号量应该停止执行并导致死锁,每次都会输出该字符串,对吧? 代码如下: #includ
我正在使用 semaphore.h,如果 n 而不是只有一个插槽可用,我想获取一个信号量。 Posix 本身不提供这个。我该如何解决这个问题?我必须使用信号量,没有其他同步方法是可能的。 我正在考虑使
我正在使用命名信号量编写一个多进程程序,在主进程中我使用以下代码打开信号量 semaphore = sem_open("/msema",O_RDWR|O_CREAT|O_TRUNC,00777,1);
我在 Linux 中写了一个关于共享内存的简单项目。两个程序共享内存,一个是向其中写入字母,第二个是从中读取字母。我决定使用信号量以确保在读取新字母之前不会生成新字母。 问题是当 sem_wait(r
为什么 sem_wait 不能在信号处理程序中使用(特别是每个线程的 SIGSEGV 信号)?有人能给我一个应用程序崩溃的示例场景吗?我想 sem_wait 既是可重入又是线程安全,那么这里的问题是什
基本上,我的程序创建了 3 个线程。 “服务器”和 2 个“ worker ”。工作人员旨在对 1000 行文件(每个线程 500 个数字)中的 3 位正整数求和。在每个 worker 对自己的部分求
我有一个由多个 pthread 使用的队列结构。如果队列不为空,线程应该从队列中出队,然后做他们的工作。 我最初将其设置为 while 循环,其中线程使用 mutex_lock 检查队列是否为空。不幸
我正在开发一个项目,其中“学生”线程将使用信号量来唤醒“TA”线程。 我有一个名为 studentNeedsHelp_Sem 的信号量 我用 sem_init(&studentNeedsHelp_Se
static int res1 = 0; static int res2 = 0; static int res3 = 0; static int counter = 0; static sem_t
我正在做一个学校项目,我们必须制作一个多线程网络服务器。当我在我的信号量上调用 sem_wait 时遇到问题(应该初始化为 0 但似乎已经被 sem_post() 编辑为 1)。我得到一个 SIGAB
我发现 sem_post 和 sem_wait 的时间间隔至少有 50 微秒。 sem_t gSema; struct timeval gTv; void *run(void *arg) {
如果您有一个线程 (thread1) 在 sem_wait() 上阻塞,而另一个线程 (thread2) 使用 sem_destroy() 破坏了那个信号量,那么会发生什么到线程 1? A quick
我是一名优秀的程序员,十分优秀!