I met a strange problem while studying the Peterson Algorithm. When I finish my program, I was told that I should restrict that two particular threads (thread1 and thread2) to a single CPU core (I don't exactly know why I should do this, but my teacher told me that if I want to run two mutual exclusion processes with single resources without conflict, multi-core CPU may cause bug so I should restrict them to a single core) so I add the SetThreadAffinityMask() to do this.
But after I added this function, my code doesn't work, it was stuck into a infinite loop in thread1, not like the result before I add this function, which is work as well as I expected.
Here's my code
#include "stdafx.h"
#include <stdlib.h>
#include <time.h>
#include <Windows.h>
int nAccount1 = 0, nAccount2 = 0;
DWORD start, end;
int flag = 0;
int Process[2] = { 0 };
int Turn = 0;
DWORD WINAPI ThreadExecutive_1(LPVOID lpParameter) {
int nLoop = 0;
int nTemp1, nTemp2, nRandom;
int* pID = (int*)lpParameter;
//printf("Thread: %d Built successfully!\n", *pID);
do {
Process[0] = 1;
Turn = 1;
while (Process[1] == 1 && Turn == 1);
nTemp1 = nAccount1;
nTemp2 = nAccount2;
nRandom = rand();
nAccount1 = nTemp1 + nRandom;
nAccount2 = nTemp2 - nRandom;
Process[0] = 0;
nLoop++;
if (nLoop % 100000 == 0) {
// printf("here thread %d\n", *pID);
}
} while (nLoop < 1000000);
//printf("Thread%d was terminated Result:nAccount1 = %d, nAccount2 = %d\n", *pID, nAccount1, nAccount2);
flag++;
return 0;
}
DWORD WINAPI ThreadExecutive_2(LPVOID lpParameter) {
int nLoop = 0;
int nTemp1, nTemp2, nRandom;
int* pID = (int*)lpParameter;
printf("Thread: %d Built successfully!\n", *pID);
do {
Process[1] = 1;
Turn = 0;
while (Process[0] == 1 && Turn == 0);
nTemp1 = nAccount1;
nTemp2 = nAccount2;
nRandom = rand();
nAccount1 = nTemp1 + nRandom;
nAccount2 = nTemp2 - nRandom;
Process[1] = 0;
nLoop++;
if (nLoop % 100000 == 0) {
printf("here thread %d\n", *pID);
}
} while (nLoop < 1000000);
printf("Thread%d was terminated Result:nAccount1 = %d, nAccount2 = %d\n", *pID, nAccount1, nAccount2);
flag++;
return 0;
}
int main()
{
start = GetTickCount();
printf("===============Peterson Algorithm================\n");
HANDLE handle1, handle2;
int Thread1 = 1;
int Thread2 = 2;
//===========This is where the problem occourred===================
handle1 = CreateThread(NULL, 0, ThreadExecutive_1, &Thread1, 0, NULL);
SetThreadAffinityMask(handle1, 0x00000001);
handle2 = CreateThread(NULL, 0, ThreadExecutive_2, &Thread2, 0, NULL);
SetThreadAffinityMask(handle2, 0x00000001);
//===========This is where the problem occourred===================
if (handle1 == NULL) {
printf("Handle1 build failed\n");
exit(0);
}
if (handle2 == NULL) {
printf("Handle2 build failed\n");
exit(0);
}
CloseHandle(handle1);
CloseHandle(handle2);
while (1) {
if (flag == 2) {
break;
}
}
end = GetTickCount();
printf("Execution time : %d\n", (end - start));
system("pause");
return 0;
}
Here are the results. Without SetThreadAffinityMask():
===============Peterson Algorithm================
Thread: 1 Built successfully!
Thread: 2 Built successfully!
here thread 1
here thread 2
here thread 1
here thread 2
here thread 1
here thread 2
here thread 1
here thread 2
here thread 1
here thread 2
here thread 1
here thread 2
here thread 1
here thread 2
here thread 1
here thread 2
here thread 1
here thread 2
here thread 1
Thread1 was terminated Result:nAccount1 = -1621397855, nAccount2 = 1621397855
here thread 2
Thread2 was terminated Result:nAccount1 = -1583839139, nAccount2 = 1583839139
Execution time : 312
With SetThreadAffinityMask():(An infinite loop occurred)
===============Peterson Algorithm================
Thread: 2 Built successfully!
here thread 2
here thread 2
here thread 2
here thread 2
Thread: 1 Built successfully!
Related
Essentially, my program creates 3 threads. The "server" and 2 "workers." The workers are meant to sum the 3 digit positive integers in a 1000 line file (500 numbers per thread). After each worker has summed its part, the server prints each workers total. The only problem is my semaphores are not seeming to work.
Here is a version of my program:
// 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;
}
I've tested with less threads more semaphores as well, with non luck. I've tried different initial semaphore values. The only time I can get the correct output is when I manually wait with sleep(5); but that defeats the purpose of this project.
A few issues ...
Each client thread does its own/private fopen but FILE *file; is global so they overwrite each others values.
We need to make this variable function scoped so each thread has its own private pointer.
There are no fclose calls.
pthread_exit should not be done by the main thread. It is only for threads created with pthread_create.
Otherwise ...
Whichever thread does the fopen last will set the final value.
So, there is a race condition and the effect is the same as if the main thread (prior to pthread_create calls) had done a single fopen, defeating the purpose of each thread doing its own fopen.
Worse yet, a given thread may do the first fopen, then start with fscanf and have its file value changed when the second thread replaces the file value, so weird stuff happens to each thread because they are doing fseek/fscanf on the same FILE * instance.
Having the aforementioned fclose calls would have made the issue more evident.
Here is the refactored code. It is annotated:
// 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;
}
In the code above, I've used cpp conditionals to denote old vs. new code:
#if 0
// old code
#else
// new code
#endif
#if 1
// new code
#endif
Note: this can be cleaned up by running the file through unifdef -k
UPDATE:
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
It's hard to compare results because we're using different datasets. I created a perl script to create some data.
Most important is that the sum reported by the given worker matches what the server sees for that worker task.
Then, if we know what each per thread section of the file should sum to, that is another matter.
The per line termination is critical (e.g.): CRLF vs LF (see below)
The actual order of worker sem_post and termination doesn't really matter. It can vary system to system or, even, invocation to invocation. What matters is that the server thread waits for N threads (i.e.) N sem_wait calls before printing any sums.
I've produced an updated version below.
Server does not "signal" a worker. The worker "signals" the server by doing sem_post and the server "receives" it by doing sem_wait
I've create a task/thread struct to hold the sums, thread IDs, etc.
I've generalized the code to allow N threads.
Added check of \n placement (i.e. line width). That is, under linux/POSIX a four digit number would be followed by LF (newline) and length would be 5. But, under windows, it would be CRLF (carriage return/newline) and length would be 6.
Added check of file size to ensure it is exactly the desired/expected length.
Some additional diagnostics.
Here is the updated code:
// 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;
}
Here is the perl script output that I used to generate the data:
number of tasks 2
element count per task 500
line separater 0A
section 0 sum 124750
section 1 sum 125250
Here is the program output:
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
Here is the perl script:
#!/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);
}
}
Hello I am having trouble with strtol
(specifically, that implicit conversion loses integer precision)
as well as with sem_open incompatible pointer types passing sem_t
I have tried to use named semaphores instead of unnamed semaphores, use sem_open instead of sem_init, and use sem_close and sem_unlink instead of sem_destroy, but still getting errors.
#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <ctype.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <fcntl.h> /* For O_* constants */
#include <sys/stat.h> /* For mode constants */
#include <semaphore.h>
// Global mutex and semaphores
pthread_mutex_t lock;
sem_t full;
sem_t empty;
// Global item to be incremented and enqueued
int global_value = 1;
// Queue
int* buffer;
int in_index;
int out_index;
// Producer and consumer arrays for comparing
int* producer_arr;
int* consumer_arr;
int p_idx = 0;
int c_idx = 0;
// Global args
int num_buffers;
int num_producers;
int num_consumers;
int items_produced;
int items_consumed;
int over_consume;
int over_consume_amount;
int p_time;
int c_time;
/*
* Function to remove item.
* Item removed is returned
*/
int dequeue_item() {
int item = buffer[out_index];
buffer[out_index] = 0;
out_index = (out_index + 1) % num_buffers;
return item;
}
/*
* Function to add item.
* Item added is returned.
* It is up to you to determine
* how to use the ruturn value.
* If you decide to not use it, then ignore
* the return value, do not change the
* return type to void.
*/
int enqueue_item(int item) {
buffer[in_index] = item;
in_index = (in_index + 1) % num_buffers;
return item;
}
void* producer(void* arg) {
int tid = *((int*) arg);
int item;
for (int i = 0; i < items_produced; i++) {
// Increment global item
item = global_value++;
// Lock semaphore and mutex
sem_wait(&empty);
pthread_mutex_lock(&lock);
// Produce item onto queue
enqueue_item(item);
producer_arr[p_idx++] = item;
printf( "%5d was produced by producer->\t%5d\n" , item, tid);
// Unlock mutex and semaphore
pthread_mutex_unlock(&lock);
sem_post(&full);
// Sleep
sleep(p_time);
}
pthread_exit(0);
}
void* consumer(void* arg) {
int tid = *((int*) arg);
int item;
if (!over_consume) {
// Either over or not required
for (int i = 0; i < items_consumed; i++) {
// Lock semaphore and mutex
sem_wait(&full);
pthread_mutex_lock(&lock);
// Consume item from queue
item = dequeue_item();
consumer_arr[c_idx++] = item;
printf( "%5d was consumed by consumer->\t%5d\n" , item, tid);
// Unlock mutex and semaphore
pthread_mutex_unlock(&lock);
sem_post(&empty);
// Sleep
sleep(c_time);
}
} else {
// Over consume if needed at the beginning of the program
over_consume = 0;
for (int i = 0; i < items_consumed + over_consume_amount; i++) {
// Lock semaphore and mutex
sem_wait(&full);
pthread_mutex_lock(&lock);
// Consume item from queue
item = dequeue_item();
consumer_arr[c_idx++] = item;
printf( "%5d was consumed by consumer->\t%5d\n" , item, tid);
// Unlock mutex and semaphore
pthread_mutex_unlock(&lock);
sem_post(&empty);
// Sleep
sleep(c_time);
}
}
pthread_exit(0);
}
/*
* $ ./pandc <N> <P> <C> <X> <Ptime> <Ctime>
* N = number of buffers to maintain
* P = number of producer threads
* C = number of consumer threads
* X = number of items each producer thread will produce
* Ptime = how long each producer thread will sleep after producing an item in seconds
* Ctime = how long each consumer thread will sleep after consuming an item in seconds
*/
int main(int argc, char** argv) {
// argv[0] is the program itself ("./pandc")
if (argc != 7) {
printf("Enter 6 arguments: \"$ ./pandc <N> <P> <C> <X> <Ptime> <Ctime>\"\n");
exit(EXIT_FAILURE);
}
// Print current time
time_t start_time = time(0);
printf( "Current time: %s\n" , ctime(&start_time));
// Read command-line args
num_buffers = strtol(argv[1], NULL, 10);
num_producers = strtol(argv[2], NULL, 10);
num_consumers = strtol(argv[3], NULL, 10);
items_produced = strtol(argv[4], NULL, 10);
items_consumed = (num_producers * items_produced) / num_consumers;
over_consume = (num_producers * items_produced) % num_consumers > 0 ? 1 : 0;
over_consume_amount = (num_producers * items_produced) - (num_consumers * items_consumed);
p_time = strtol(argv[5], NULL, 10);
c_time = strtol(argv[6], NULL, 10);
// Print producer-consumer problem information
printf("\t Number of Buffers : %5d\n", num_buffers);
printf("\t Number of Producers : %5d\n", num_producers);
printf("\t Number of Consumers : %5d\n", num_consumers);
printf("\tNumber of items Produced by each producer : %5d\n", items_produced);
printf("\tNumber of items Consumed by each consumer : %5d\n", items_consumed);
printf("\t Over consume on? : %5s\n", (over_consume) ? "yes" : "no");
printf("\t Over consume amount : %5d\n", over_consume_amount);
printf("\t Time each Producer Sleeps (seconds) : %5d\n", p_time);
printf("\t Time each Consumer Sleeps (seconds) : %5d\n", c_time);
printf("\n");
// Initialize mutex, semaphore, buffer, arrays
pthread_mutex_init(&lock, NULL); // mutex lock = 1;
sem_open( &full, 0, 0); // semaphore full = 0;
sem_open( &empty, 0, num_buffers); // semaphore empty = N;
buffer = malloc(sizeof(int*) * num_buffers); // buffer[N];
producer_arr = malloc(sizeof(int*) * num_producers * items_produced);
consumer_arr = malloc(sizeof(int*) * num_producers * items_produced);
// consumer_arr = malloc(sizeof(int*) * num_consumers * items_consumed);
in_index = 0;
out_index = 0;
// New threads
pthread_t producer_ids[num_producers];
pthread_t consumer_ids[num_consumers];
// Create producer and consumer threads
for (int i = 0; i < num_producers; i++) {
int id = i + 1;
pthread_create(&producer_ids[i], NULL, &producer, (void*) &id);
}
for (int i = 0; i < num_consumers; i++) {
int id = i + 1;
pthread_create(&consumer_ids[i], NULL, &consumer, (void*) &id);
}
// Join producer and consumer threads
for (int i = 0; i < num_producers; i++) {
pthread_join(producer_ids[i], NULL);
printf( "Producer thread joined:%5d\n" , i);
}
for (int i = 0; i < num_consumers; i++) {
pthread_join(consumer_ids[i], NULL);
printf( "Consumer thread joined:%5d\n" , i);
}
time_t end_time = time(0);
printf( "Current time: %s\n" , ctime(&end_time));
// Compare and match producer and consumer arrays
int match = 1; // Start out as true
fprintf(stderr, "Producer Array\t| Consumer Array\n");
for (int i = 0; i < num_producers * items_produced; i++) {
fprintf(stderr, "%d\t\t\t\t| %d\n", producer_arr[i], consumer_arr[i]);
if (producer_arr[i] != consumer_arr[i]) {
match = 0; // False when mismatch detected
}
}
fprintf(stderr, "\nConsume and Produce Arrays %s!\n", (match) ? "Match" : "DO NOT Match");
fprintf(stderr, "\nTotal Runtime: %d secs\n", (int) (end_time - start_time));
// Cleanup
pthread_mutex_destroy(&lock);
sem_unlink(&full);
sem_unlink(&empty);
free(buffer);
return 0;
}
I have problem creating thousands of threads and closing it.
Look at this code:
HANDLE threadHandles[i];
for(int i = 0; i < 1000; i++)
{
CreateThread(0, 0, &func, 0, CREATE_SUSPENDED, threadHandles[i]);
printf("%i - %i\n", i, threadHandles[i]);
CloseHandle(threadHandles[i])
}
printf("Last Error is %i", GetLastError());
It should proceed this output:
0 - 236423
1 - 23456236
2 - 2373547
3 - 73521346
4 - 23456775
5 - 78543683465
...
2998 - 754752
2999 - 23462346
Last Error is 0
like this.
But actually it will print nothing. Why? Because one of the created threads had a conflict with stdout handle.
I realized it using this code:
HANDLE stdout = GetStdHandle(STD_OUTPUT_HANDLE);
HANDLE threadHandles[i];
for(int i = 0; i < 1000; i++)
{
CreateThread(0, 0, &func, 0, CREATE_SUSPENDED, threadHandles[i]);
printf("%i - %i\n", i, threadHandles[i]);
if(threadHandles[i] != stdout) // I have stdout == 12 on my machine
CloseHandle(threadHandles[i])
}
and it worked like this:
0 - 236423
1 - 23456236
2 - 2373547
3 - 0
4 - 23456775
5 - 78543683465
...
2998 - 0
2999 - 23462346
Last Error is 6
Where is the problem? Why there is a conflict between created handles and existing standard handles?
The thread handle is returned by the function! The last parameter receives the thread id, not the handle.
HANDLE threadHandles[1000] = { 0 };
UINT i;
for (i = 0; i < 1000; ++i)
{
DWORD threadId;
threadHandles[i] = CreateThread(0, 0, &func, 0, /*CREATE_SUSPENDED*/0, &threadId);
if (!threadHandles[i])
{
printf("Failed to create thread, error %u\n", GetLastError());
break;
}
printf("Thread #%u: handle=%p id=%u\n", i, threadHandles[i], threadId);
// Not closing the handle here so the example will show unique thread handles and ids: CloseHandle(threadHandles[i]), threadHandles[i] = NULL;
}
// TODO: Wait for threads or do some other work?
for (i = 0; i < 1000; ++i)
if (threadHandles[i])
CloseHandle(threadHandles[i]);
On my machine this prints
Thread #0: handle=0000002C id=16424
Thread #1: handle=00000030 id=21192
Thread #2: handle=00000034 id=21180
Thread #3: handle=00000038 id=17336
Thread #4: handle=0000003C id=21184
Thread #5: handle=00000040 id=4460
...
Thread #991: handle=00000FE8 id=12280
Thread #992: handle=00000FEC id=20360
Thread #993: handle=00000FF0 id=20328
Thread #994: handle=00000FF4 id=16060
Thread #995: handle=00000FF8 id=4556
Thread #996: handle=00000FFC id=20296
Thread #997: handle=00001004 id=10316
Thread #998: handle=00001008 id=20604
Thread #999: handle=0000100C id=20264
This is for an Operating Systems programming assignment. I'm attempting to read n number of files, use threads to search each file for a number of occurrences for a specific character.
./mycount j new.txt some.txt here.txt hello.txt
The output for my test code as is should be:
argumentCount: 6
threadCount: 4
pthread_create() for thread 0 returns: 0
Thread 1
pthread_create() for thread 1 returns: 0
Thread 2
pthread_create() for thread 2 returns: 0
Thread 3
pthread_create() for thread 3 returns: 0
Thread 4
However each execution of mycount is different, with the last thread usually not executing/printing. Either that or they'll print sporadically, in tandem, etc.
I'm attempting to utilize a mutex to ensure the integrity of my data but I'm not sure what's really happening behind the scenes.
How do I ensure that everything finishes the same way each time? The last thread always returns 0, but it sometimes won't execute the function I give it completely.
Code:
//GLOBALS
int occurrences = 0;
//PROTOTYPES
void *scanFile( void *filePtr );
//Initialize space for mutex.
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
//Receive arguments from .exe call
void main ( int argumentCount, char *argumentVariables[] )
{
//Exit if argumentCount is > 50.
if (argumentCount > 50)
{
perror("Too many arguments. Enter less than 50.\n");
exit(EXIT_FAILURE);
}
printf("argumentCount: %d \n", argumentCount);
//Instantiate variables.
//i - iterator
//*newCommand - Used to hold string value of first command entered.
//*newVector - Used to hold string of the rest of the commands. Is a vector.
int i;
char *searchCharacter;
char *newVector[argumentCount];
//Iterate through command line arguments and split them.
for (i = 0; i < argumentCount; i++)
{
searchCharacter = argumentVariables[1];
if (i < argumentCount - 1)
{
newVector[i] = argumentVariables[1 + i];
}
else
{
newVector[i] = NULL;
}
}
//Exit if newest command is NULL.
if (searchCharacter == NULL)
{
perror("No character entered!\n");
exit(EXIT_FAILURE);
}
int threads = argumentCount - 2;
printf("threadCount: %d \n", threads);
pthread_t * thread = malloc(sizeof(pthread_t)*threads);
for (int i = 0; i < threads; i++)
{
int ret;
char *message = "Thread";
ret = pthread_create(&thread[i], NULL, scanFile, (void*) message);
if (ret != 0)
{
printf("Error - pthread_create() return code: %d\n", ret);
exit(EXIT_FAILURE);
}
printf("pthread_create() for thread %d returns: %d\n", i, ret);
}
exit(EXIT_SUCCESS);
}
void *scanFile( void *filePtr )
{
pthread_mutex_lock( &mutex );
char *message;
message = (char *) filePtr;
occurrences += 1;
printf("%s %d\n", message, occurrences);
pthread_mutex_unlock( &mutex );
}
Found the solution thanks to user2864740 and Ken Thomases.
Added:
for (int j = 0; j < threads; j++)
{
//Join the threads so all the data is good to go.
pthread_join(thread[j], NULL);
}
Correction:
for (int i = 0; i < threads; i++)
{
request[i].file = argumentVariables[i + 2];
request[i].character = searchCharacter;
//Create the thread. Any output from the integer newThread is an error code.
newThread = pthread_create(&thread[i], NULL, *scanFile, &request[i]);
if (newThread != 0)
{
printf("Error - pthread_create() return code: %d\n", newThread);
exit(EXIT_FAILURE);
}
}
for (int j = 0; j < threads; j++)
{
//Join the threads so all the data is good to go.
pthread_join(thread[j], NULL);
}
assume creating 3 worker threads by pthread_create,
in these worker thread routine, each call a simple infinite loop function which do not have a return to do counting
how to make worker thread gain control after calling infinite loop function and save the context of infinite loop function for calling in worker thread again?
Let me rephrase to see if I understood the problem.
You have a master thread which spawns 3 worker threads which each do a long running (infinite) job.
At a certain point you want to interrupt processing, save the state of all threads to resume where they left off at a later time.
I think the best way of doing this is organize your threads work in transactionally bound chunks. When restarting, you check the last completed transaction, and go from there.
But since I suspect this to be a homework assignment in low level thread plumbing, may i suggest a shared boolean which is checked on every time you go through the loop to exit and store the state afterwards. Aternatively "kill" the thread and catch the exception and store the state. The last option is messy.
I think you should clarify your question.
If every worker thread calls an infinite loop then I suppose that your master thread would have to call pthread_cancel() on each of them. From what I gather this might require calls to other pthread_*() functions to set the "cancelability" of the target threads.
Of course this suggestion begs the question. The vastly preferable approach would be to prevent those infinite loops. Write your code so that it has exit conditions ... so that the work is bounded by some sort of input or has some sort of event handling.
want to do the effect of a threadpool, after calling infinite loop function, each worker thread can change other tasks(other infinite loop function) to run
for example 3 worker thread can run 4 tasks(infinite loop functions)
#ifndef JOB_CPP
#define JOB_CPP
#include "job.h"
#define NUM_OF_TASKS 4
#define NUM_OF_WORKERS 3
void (* job_queue[NUM_OF_TASKS])(void*);
void (* fp[NUM_OF_WORKERS])(void*); // original running job
int running_task[NUM_OF_WORKERS];
int idle[NUM_OF_TASKS];
int last_running_task[NUM_OF_WORKERS];
int no_of_tasks_running[NUM_OF_WORKERS];
my_struct_t data = {PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER, 0};
void func1(void *arg)
{
int count = 0;
int status;
while(true)
{
//if((count % 100) == 0)
//printf("func1 run %d\n", count);
count = count + 1;
//status = pthread_cond_signal(&data.cv);
}
}
void func2(void *arg)
{
int count = 0;
int status;
while(true)
{
//printf("func2 run %d\n", count);
count = count + 1;
//status = pthread_cond_signal(&data.cv);
}
}
void func3(void *arg)
{ int count = 0;
int status;
while(true)
{
//printf("func3 run %d\n", count);
count = count + 1;
//status = pthread_cond_signal(&data.cv);
}
}
void func4(void *arg)
{ int count = 0;
int status;
while(true)
{
//printf("func4 run %d\n", count);
count = count + 1;
//status = pthread_cond_signal(&data.done);
}
}
void jobinit()
{
for(int i=0; i<NUM_OF_TASKS; i++)
{
job_queue[i] = NULL;
idle[i] = 0;
}
for(int i=0; i<NUM_OF_WORKERS; i++)
{
fp[i] = NULL;
running_task[i] = 0;
last_running_task[i] = 0;
no_of_tasks_running[i] = 0;
}
jobadd(func1);
jobadd(func2);
jobadd(func3);
jobadd(func4);
jobrun();
}
void jobadd(void (*job)(void*))
{
for(int i=0; i<4; i++)
{
if(job_queue[i] == NULL)
{
job_queue[i] = job;
return;
}
}
}
void* workserver(void *arg);
void* workserver(void *arg)
{
int status, timedout;
struct timespec timeout;
status = pthread_mutex_lock(&data.mutex);
while(true)
{
timedout = 0;
clock_gettime(CLOCK_REALTIME, &timeout);
timeout.tv_sec += 2;
sleep(1);
//void (* clean)(void*);
status = pthread_cond_timedwait(&data.cv, &data.mutex, &timeout);
if(status == ETIMEDOUT){
printf("worker wait timed out %d\n", (int)arg);
timedout = 1;
}else if(status != 0){
printf("worker wait failed %d\n", (int)arg);
status = pthread_mutex_unlock(&data.mutex);
return NULL;
}
printf("workserver number: %d\n", (int)arg);
status = pthread_mutex_unlock(&data.mutex);
printf("function run %d\n", (int)arg);
(* job_queue[(int)arg])(NULL);
printf("cond wait start %d\n", (int)arg);
status = pthread_cond_wait(&data.done, &data.mutex);
printf("cond wait end\n");
status = pthread_mutex_lock(&data.mutex);
}
}
void jobrun()
{
for(int i=0; i<3; i++) {idle[i] = 0;}
pthread_t r1_threadid[3];
for(int i=0; i<3; i++)
{
pthread_create(&r1_threadid[i], NULL, workserver, (void*)i);
}
int status;
struct timespec timeout;
timeout.tv_sec = time (NULL) + 2;
timeout.tv_nsec = 0;
while(true)
{
status = pthread_mutex_lock(&data.mutex);
while(data.value == 0)
{
status = pthread_cond_timedwait(&data.cond, &data.mutex, &timeout);
}
if(data.value != 0)
{
//printf("condition was signaled\n");
data.value = 0;
}
status = pthread_mutex_unlock(&data.mutex);
if(status != 0)
printf("unlock mutex error");
}
}
#endif